mirror of
https://github.com/bevyengine/bevy
synced 2024-11-22 20:53:53 +00:00
30 commits
Author | SHA1 | Message | Date | |
---|---|---|---|---|
JMS55
|
fcd7c0fc3d
|
Exposure settings (adopted) (#11347)
Rebased and finished version of https://github.com/bevyengine/bevy/pull/8407. Huge thanks to @GitGhillie for adjusting all the examples, and the many other people who helped write this PR (@superdump , @coreh , among others) :) Fixes https://github.com/bevyengine/bevy/issues/8369 --- ## Changelog - Added a `brightness` control to `Skybox`. - Added an `intensity` control to `EnvironmentMapLight`. - Added `ExposureSettings` and `PhysicalCameraParameters` for controlling exposure of 3D cameras. - Removed the baked-in `DirectionalLight` exposure Bevy previously hardcoded internally. ## Migration Guide - If using a `Skybox` or `EnvironmentMapLight`, use the new `brightness` and `intensity` controls to adjust their strength. - All 3D scene will now have different apparent brightnesses due to Bevy implementing proper exposure controls. You will have to adjust the intensity of your lights and/or your camera exposure via the new `ExposureSettings` component to compensate. --------- Co-authored-by: Robert Swain <robert.swain@gmail.com> Co-authored-by: GitGhillie <jillisnoordhoek@gmail.com> Co-authored-by: Marco Buono <thecoreh@gmail.com> Co-authored-by: vero <email@atlasdostal.com> Co-authored-by: atlas dostal <rodol@rivalrebels.com> |
||
Joona Aalto
|
a795de30b4
|
Use impl Into<A> for Assets::add (#10878)
# Motivation When spawning entities into a scene, it is very common to create assets like meshes and materials and to add them via asset handles. A common setup might look like this: ```rust fn setup( mut commands: Commands, mut meshes: ResMut<Assets<Mesh>>, mut materials: ResMut<Assets<StandardMaterial>>, ) { commands.spawn(PbrBundle { mesh: meshes.add(Mesh::from(shape::Cube { size: 1.0 })), material: materials.add(StandardMaterial::from(Color::RED)), ..default() }); } ``` Let's take a closer look at the part that adds the assets using `add`. ```rust mesh: meshes.add(Mesh::from(shape::Cube { size: 1.0 })), material: materials.add(StandardMaterial::from(Color::RED)), ``` Here, "mesh" and "material" are both repeated three times. It's very explicit, but I find it to be a bit verbose. In addition to being more code to read and write, the extra characters can sometimes also lead to the code being formatted to span multiple lines even though the core task, adding e.g. a primitive mesh, is extremely simple. A way to address this is by using `.into()`: ```rust mesh: meshes.add(shape::Cube { size: 1.0 }.into()), material: materials.add(Color::RED.into()), ``` This is fine, but from the names and the type of `meshes`, we already know what the type should be. It's very clear that `Cube` should be turned into a `Mesh` because of the context it's used in. `.into()` is just seven characters, but it's so common that it quickly adds up and gets annoying. It would be nice if you could skip all of the conversion and let Bevy handle it for you: ```rust mesh: meshes.add(shape::Cube { size: 1.0 }), material: materials.add(Color::RED), ``` # Objective Make adding assets more ergonomic by making `Assets::add` take an `impl Into<A>` instead of `A`. ## Solution `Assets::add` now takes an `impl Into<A>` instead of `A`, so e.g. this works: ```rust commands.spawn(PbrBundle { mesh: meshes.add(shape::Cube { size: 1.0 }), material: materials.add(Color::RED), ..default() }); ``` I also changed all examples to use this API, which increases consistency as well because `Mesh::from` and `into` were being used arbitrarily even in the same file. This also gets rid of some lines of code because formatting is nicer. --- ## Changelog - `Assets::add` now takes an `impl Into<A>` instead of `A` - Examples don't use `T::from(K)` or `K.into()` when adding assets ## Migration Guide Some `into` calls that worked previously might now be broken because of the new trait bounds. You need to either remove `into` or perform the conversion explicitly with `from`: ```rust // Doesn't compile let mesh_handle = meshes.add(shape::Cube { size: 1.0 }.into()), // These compile let mesh_handle = meshes.add(shape::Cube { size: 1.0 }), let mesh_handle = meshes.add(Mesh::from(shape::Cube { size: 1.0 })), ``` ## Concerns I believe the primary concerns might be: 1. Is this too implicit? 2. Does this increase codegen bloat? Previously, the two APIs were using `into` or `from`, and now it's "nothing" or `from`. You could argue that `into` is slightly more explicit than "nothing" in cases like the earlier examples where a `Color` gets converted to e.g. a `StandardMaterial`, but I personally don't think `into` adds much value even in this case, and you could still see the actual type from the asset type. As for codegen bloat, I doubt it adds that much, but I'm not very familiar with the details of codegen. I personally value the user-facing code reduction and ergonomics improvements that these changes would provide, but it might be worth checking the other effects in more detail. Another slight concern is migration pain; apps might have a ton of `into` calls that would need to be removed, and it did take me a while to do so for Bevy itself (maybe around 20-40 minutes). However, I think the fact that there *are* so many `into` calls just highlights that the API could be made nicer, and I'd gladly migrate my own projects for it. |
||
Thierry Berger
|
ced216f59a
|
Update winit dependency to 0.29 (#10702)
# Objective - Update winit dependency to 0.29 ## Changelog ### KeyCode changes - Removed `ScanCode`, as it was [replaced by KeyCode](https://github.com/rust-windowing/winit/blob/master/CHANGELOG.md#0292). - `ReceivedCharacter.char` is now a `SmolStr`, [relevant doc](https://docs.rs/winit/latest/winit/event/struct.KeyEvent.html#structfield.text). - Changed most `KeyCode` values, and added more. KeyCode has changed meaning. With this PR, it refers to physical position on keyboard rather than the printed letter on keyboard keys. In practice this means: - On QWERTY keyboard layouts, nothing changes - On any other keyboard layout, `KeyCode` no longer reflects the label on key. - This is "good". In bevy 0.12, when you used WASD for movement, users with non-QWERTY keyboards couldn't play your game! This was especially bad for non-latin keyboards. Now, WASD represents the physical keys. A French player will press the ZQSD keys, which are near each other, Kyrgyz players will use "Цфыв". - This is "bad" as well. You can't know in advance what the label of the key for input is. Your UI says "press WASD to move", even if in reality, they should be pressing "ZQSD" or "Цфыв". You also no longer can use `KeyCode` for text inputs. In any case, it was a pretty bad API for text input. You should use `ReceivedCharacter` now instead. ### Other changes - Use `web-time` rather than `instant` crate. (https://github.com/rust-windowing/winit/pull/2836) - winit did split `run_return` in `run_onDemand` and `pump_events`, I did the same change in bevy_winit and used `pump_events`. - Removed `return_from_run` from `WinitSettings` as `winit::run` now returns on supported platforms. - I left the example "return_after_run" as I think it's still useful. - This winit change is done partly to allow to create a new window after quitting all windows: https://github.com/emilk/egui/issues/1918 ; this PR doesn't address. - added `width` and `height` properties in the `canvas` from wasm example (https://github.com/bevyengine/bevy/pull/10702#discussion_r1420567168) ## Known regressions (important follow ups?) - Provide an API for reacting when a specific key from current layout was released. - possible solutions: use winit::Key from winit::KeyEvent ; mapping between KeyCode and Key ; or . - We don't receive characters through alt+numpad (e.g. alt + 151 = "ù") anymore ; reproduced on winit example "ime". maybe related to https://github.com/rust-windowing/winit/issues/2945 - (windows) Window content doesn't refresh at all when resizing. By reading https://github.com/rust-windowing/winit/issues/2900 ; I suspect we should just fire a `window.request_redraw();` from `AboutToWait`, and handle actual redrawing within `RedrawRequested`. I'm not sure how to move all that code so I'd appreciate it to be a follow up. - (windows) unreleased winit fix for using set_control_flow in AboutToWait https://github.com/rust-windowing/winit/issues/3215 ; ⚠️ I'm not sure what the implications are, but that feels bad 🤔 ## Follow up I'd like to avoid bloating this PR, here are a few follow up tasks worthy of a separate PR, or new issue to track them once this PR is closed, as they would either complicate reviews, or at risk of being controversial: - remove CanvasParentResizePlugin (https://github.com/bevyengine/bevy/pull/10702#discussion_r1417068856) - avoid mentionning explicitly winit in docs from bevy_window ? - NamedKey integration on bevy_input: https://github.com/rust-windowing/winit/pull/3143 introduced a new NamedKey variant. I implemented it only on the converters but we'd benefit making the same changes to bevy_input. - Add more info in KeyboardInput https://github.com/bevyengine/bevy/pull/10702#pullrequestreview-1748336313 - https://github.com/bevyengine/bevy/pull/9905 added a workaround on a bug allegedly fixed by winit 0.29. We should check if it's still necessary. - update to raw_window_handle 0.6 - blocked by wgpu - Rename `KeyCode` to `PhysicalKeyCode` https://github.com/bevyengine/bevy/pull/10702#discussion_r1404595015 - remove `instant` dependency, [replaced by](https://github.com/rust-windowing/winit/pull/2836) `web_time`), we'd need to update to : - fastrand >= 2.0 - [`async-executor`](https://github.com/smol-rs/async-executor) >= 1.7 - [`futures-lite`](https://github.com/smol-rs/futures-lite) >= 2.0 - Verify license, see [discussion](https://github.com/bevyengine/bevy/pull/8745#discussion_r1402439800) - we might be missing a short notice or description of changes made - Consider using https://github.com/rust-windowing/cursor-icon directly rather than vendoring it in bevy. - investigate [this unwrap](https://github.com/bevyengine/bevy/pull/8745#discussion_r1387044986) (`winit_window.canvas().unwrap();`) - Use more good things about winit's update - https://github.com/bevyengine/bevy/pull/10689#issuecomment-1823560428 ## Migration Guide This PR should have one. |
||
Mateusz Wachowiak
|
1f97717a3d
|
Rename Input to ButtonInput (#10859)
# Objective - Resolves #10853 ## Solution - ~~Changed the name of `Input` struct to `PressableInput`.~~ - Changed the name of `Input` struct to `ButtonInput`. ## Migration Guide - Breaking Change: Users need to rename `Input` to `ButtonInput` in their projects. |
||
IceSentry
|
068e42a01f
|
Configurable colors for wireframe (#5303)
# Objective - Make the wireframe colors configurable at the global level and the single mesh level - Based on https://github.com/bevyengine/bevy/pull/5314 This video shows what happens when playing with various settings from the example https://github.com/bevyengine/bevy/assets/8348954/1ee9aee0-fab7-4da8-bc5d-8d0562bb34e6 ## Solution - Add a `color` field to the `WireframeMaterial` - Use a `WireframeColor` component to configure the color per entity - Add a `default_color` field to `WireframeConfig` for global wireframes or wireframes with no specified color. ## Notes - Most of the docs and the general idea for `WireframeColor` came from [UberLambda](https://github.com/UberLambda) in #3677 but the code ended up completely different so I created a separate branch. ~~I'm not sure how to correctly credit them on this PR.~~ (I re-created the commit but I added them as co-author in the commit message) ~~Closes https://github.com/bevyengine/bevy/pull/3677~~ ~~Closes https://github.com/bevyengine/bevy/pull/5301~~ ~~https://github.com/bevyengine/bevy/pull/5314 should be merged before this PR.~~ |
||
IceSentry
|
e05a9f9315
|
use Material for wireframes (#5314)
# Objective - Use the `Material` abstraction for the Wireframes - Right now this doesn't have many benefits other than simplifying some of the rendering code - We can reuse the default vertex shader and avoid rendering inconsistencies - The goal is to have a material with a color on each mesh so this approach will make it easier to implement - Originally done in https://github.com/bevyengine/bevy/pull/5303 but I decided to split the Material part to it's own PR and then adding per-entity colors and globally configurable colors will be a much simpler diff. ## Solution - Use the new `Material` abstraction for the Wireframes ## Notes It's possible this isn't ideal since this adds a `Handle<WireframeMaterial>` to all the meshes compared to the original approach that didn't need anything. I didn't notice any performance impact on my machine. This might be a surprising usage of `Material` at first, because intuitively you only have one material per mesh, but the way it's implemented you can have as many different types of materials as you want on a mesh. ## Migration Guide `WireframePipeline` was removed. If you were using it directly, please create an issue explaining your use case. --------- Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com> |
||
IceSentry
|
a962240866
|
Alternate wireframe override api (#10023)
# Objective https://github.com/bevyengine/bevy/pull/7328 introduced an API to override the global wireframe config. I believe it is flawed for a few reasons. This PR uses a non-breaking API. Instead of making the `Wireframe` an enum I introduced the `NeverRenderWireframe` component. Here's the reason why I think this is better: - Easier to migrate since it doesn't change the old behaviour. Essentially nothing to migrate. Right now this PR is a breaking change but I don't think it has to be. - It's similar to other "per mesh" rendering features like NotShadowCaster/NotShadowReceiver - It doesn't force new users to also think about global vs not global if all they want is to render a wireframe - This would also let you filter at the query definition level instead of filtering when running the query ## Solution - Introduce a `NeverRenderWireframe` component that ignores the global config --- ## Changelog - Added a `NeverRenderWireframe` component that ignores the global `WireframeConfig` |
||
Wybe Westra
|
f9e50e767b
|
Allow overriding global wireframe setting. (#7328)
# Objective Allow the user to choose between "Add wireframes to these specific entities" or "Add wireframes to everything _except_ these specific entities". Fixes #7309 # Solution Make the `Wireframe` component act like an override to the global configuration. Having `global` set to `false`, and adding a `Wireframe` with `enable: true` acts exactly as before. But now the opposite is also possible: Set `global` to `true` and add a `Wireframe` with `enable: false` will draw wireframes for everything _except_ that entity. Updated the example to show how overriding the global config works. |
||
piper
|
bc88f33e48
|
Allow other plugins to create renderer resources (#9925)
This is a duplicate of #9632, it was created since I forgot to make a new branch when I first made this PR, so I was having trouble resolving merge conflicts, meaning I had to rebuild my PR. # Objective - Allow other plugins to create the renderer resources. An example of where this would be required is my [OpenXR plugin](https://github.com/awtterpip/bevy_openxr) ## Solution - Changed the bevy RenderPlugin to optionally take precreated render resources instead of a configuration. ## Migration Guide The `RenderPlugin` now takes a `RenderCreation` enum instead of `WgpuSettings`. `RenderSettings::default()` returns `RenderSettings::Automatic(WgpuSettings::default())`. `RenderSettings` also implements `From<WgpuSettings>`. ```rust // before RenderPlugin { wgpu_settings: WgpuSettings { ... }, } // now RenderPlugin { render_creation: RenderCreation::Automatic(WgpuSettings { ... }), } // or RenderPlugin { render_creation: WgpuSettings { ... }.into(), } ``` --------- Co-authored-by: Malek <pocmalek@gmail.com> Co-authored-by: Robert Swain <robert.swain@gmail.com> |
||
Edgar Geier
|
f18f28874a
|
Allow tuples and single plugins in add_plugins , deprecate add_plugin (#8097)
# Objective - Better consistency with `add_systems`. - Deprecating `add_plugin` in favor of a more powerful `add_plugins`. - Allow passing `Plugin` to `add_plugins`. - Allow passing tuples to `add_plugins`. ## Solution - `App::add_plugins` now takes an `impl Plugins` parameter. - `App::add_plugin` is deprecated. - `Plugins` is a new sealed trait that is only implemented for `Plugin`, `PluginGroup` and tuples over `Plugins`. - All examples, benchmarks and tests are changed to use `add_plugins`, using tuples where appropriate. --- ## Changelog ### Changed - `App::add_plugins` now accepts all types that implement `Plugins`, which is implemented for: - Types that implement `Plugin`. - Types that implement `PluginGroup`. - Tuples (up to 16 elements) over types that implement `Plugins`. - Deprecated `App::add_plugin` in favor of `App::add_plugins`. ## Migration Guide - Replace `app.add_plugin(plugin)` calls with `app.add_plugins(plugin)`. --------- Co-authored-by: Carter Anderson <mcanders1@gmail.com> |
||
Carter Anderson
|
aefe1f0739
|
Schedule-First: the new and improved add_systems (#8079)
Co-authored-by: Mike <mike.hsu@gmail.com> |
||
woodroww
|
1bd390806f |
added subdivisions to shape::Plane (#7546)
# Objective There was issue #191 requesting subdivisions on the shape::Plane. I also could have used this recently. I then write the solution. Fixes #191 ## Solution I changed the shape::Plane to include subdivisions field and the code to create the subdivisions. I don't know how people are counting subdivisions so as I put in the doc comments 0 subdivisions results in the original geometry of the Plane. Greater then 0 results in the number of lines dividing the plane. I didn't know if it would be better to create a new struct that implemented this feature, say SubdivisionPlane or change Plane. I decided on changing Plane as that was what the original issue was. It would be trivial to alter this to use another struct instead of altering Plane. The issues of migration, although small, would be eliminated if a new struct was implemented. ## Changelog ### Added Added subdivisions field to shape::Plane ## Migration Guide All the examples needed to be updated to initalize the subdivisions field. Also there were two tests in tests/window that need to be updated. A user would have to update all their uses of shape::Plane to initalize the subdivisions field. |
||
ira
|
15b19b930c |
Move 'startup' Resource WgpuSettings into the RenderPlugin (#6946)
# Objective The `WgpuSettings` resource is only used during plugin build. Move it into the `RenderPlugin` struct. Changing these settings requires re-initializing the render context, which is currently not supported. If it is supported in the future it should probably be more explicit than changing a field on a resource, maybe something similar to the `CreateWindow` event. ## Migration Guide ```rust // Before (0.9) App::new() .insert_resource(WgpuSettings { .. }) .add_plugins(DefaultPlugins) // After (0.10) App::new() .add_plugins(DefaultPlugins.set(RenderPlugin { wgpu_settings: WgpuSettings { .. }, })) ``` Co-authored-by: devil-ira <justthecooldude@gmail.com> |
||
Carter Anderson
|
01aedc8431 |
Spawn now takes a Bundle (#6054)
# Objective Now that we can consolidate Bundles and Components under a single insert (thanks to #2975 and #6039), almost 100% of world spawns now look like `world.spawn().insert((Some, Tuple, Here))`. Spawning an entity without any components is an extremely uncommon pattern, so it makes sense to give spawn the "first class" ergonomic api. This consolidated api should be made consistent across all spawn apis (such as World and Commands). ## Solution All `spawn` apis (`World::spawn`, `Commands:;spawn`, `ChildBuilder::spawn`, and `WorldChildBuilder::spawn`) now accept a bundle as input: ```rust // before: commands .spawn() .insert((A, B, C)); world .spawn() .insert((A, B, C); // after commands.spawn((A, B, C)); world.spawn((A, B, C)); ``` All existing instances of `spawn_bundle` have been deprecated in favor of the new `spawn` api. A new `spawn_empty` has been added, replacing the old `spawn` api. By allowing `world.spawn(some_bundle)` to replace `world.spawn().insert(some_bundle)`, this opened the door to removing the initial entity allocation in the "empty" archetype / table done in `spawn()` (and subsequent move to the actual archetype in `.insert(some_bundle)`). This improves spawn performance by over 10%: ![image](https://user-images.githubusercontent.com/2694663/191627587-4ab2f949-4ccd-4231-80eb-80dd4d9ad6b9.png) To take this measurement, I added a new `world_spawn` benchmark. Unfortunately, optimizing `Commands::spawn` is slightly less trivial, as Commands expose the Entity id of spawned entities prior to actually spawning. Doing the optimization would (naively) require assurances that the `spawn(some_bundle)` command is applied before all other commands involving the entity (which would not necessarily be true, if memory serves). Optimizing `Commands::spawn` this way does feel possible, but it will require careful thought (and maybe some additional checks), which deserves its own PR. For now, it has the same performance characteristics of the current `Commands::spawn_bundle` on main. **Note that 99% of this PR is simple renames and refactors. The only code that needs careful scrutiny is the new `World::spawn()` impl, which is relatively straightforward, but it has some new unsafe code (which re-uses battle tested BundlerSpawner code path).** --- ## Changelog - All `spawn` apis (`World::spawn`, `Commands:;spawn`, `ChildBuilder::spawn`, and `WorldChildBuilder::spawn`) now accept a bundle as input - All instances of `spawn_bundle` have been deprecated in favor of the new `spawn` api - World and Commands now have `spawn_empty()`, which is equivalent to the old `spawn()` behavior. ## Migration Guide ```rust // Old (0.8): commands .spawn() .insert_bundle((A, B, C)); // New (0.9) commands.spawn((A, B, C)); // Old (0.8): commands.spawn_bundle((A, B, C)); // New (0.9) commands.spawn((A, B, C)); // Old (0.8): let entity = commands.spawn().id(); // New (0.9) let entity = commands.spawn_empty().id(); // Old (0.8) let entity = world.spawn().id(); // New (0.9) let entity = world.spawn_empty(); ``` |
||
Carter Anderson
|
f487407e07 |
Camera Driven Rendering (#4745)
This adds "high level camera driven rendering" to Bevy. The goal is to give users more control over what gets rendered (and where) without needing to deal with render logic. This will make scenarios like "render to texture", "multiple windows", "split screen", "2d on 3d", "3d on 2d", "pass layering", and more significantly easier. Here is an [example of a 2d render sandwiched between two 3d renders (each from a different perspective)](https://gist.github.com/cart/4fe56874b2e53bc5594a182fc76f4915): ![image](https://user-images.githubusercontent.com/2694663/168411086-af13dec8-0093-4a84-bdd4-d4362d850ffa.png) Users can now spawn a camera, point it at a RenderTarget (a texture or a window), and it will "just work". Rendering to a second window is as simple as spawning a second camera and assigning it to a specific window id: ```rust // main camera (main window) commands.spawn_bundle(Camera2dBundle::default()); // second camera (other window) commands.spawn_bundle(Camera2dBundle { camera: Camera { target: RenderTarget::Window(window_id), ..default() }, ..default() }); ``` Rendering to a texture is as simple as pointing the camera at a texture: ```rust commands.spawn_bundle(Camera2dBundle { camera: Camera { target: RenderTarget::Texture(image_handle), ..default() }, ..default() }); ``` Cameras now have a "render priority", which controls the order they are drawn in. If you want to use a camera's output texture as a texture in the main pass, just set the priority to a number lower than the main pass camera (which defaults to `0`). ```rust // main pass camera with a default priority of 0 commands.spawn_bundle(Camera2dBundle::default()); commands.spawn_bundle(Camera2dBundle { camera: Camera { target: RenderTarget::Texture(image_handle.clone()), priority: -1, ..default() }, ..default() }); commands.spawn_bundle(SpriteBundle { texture: image_handle, ..default() }) ``` Priority can also be used to layer to cameras on top of each other for the same RenderTarget. This is what "2d on top of 3d" looks like in the new system: ```rust commands.spawn_bundle(Camera3dBundle::default()); commands.spawn_bundle(Camera2dBundle { camera: Camera { // this will render 2d entities "on top" of the default 3d camera's render priority: 1, ..default() }, ..default() }); ``` There is no longer the concept of a global "active camera". Resources like `ActiveCamera<Camera2d>` and `ActiveCamera<Camera3d>` have been replaced with the camera-specific `Camera::is_active` field. This does put the onus on users to manage which cameras should be active. Cameras are now assigned a single render graph as an "entry point", which is configured on each camera entity using the new `CameraRenderGraph` component. The old `PerspectiveCameraBundle` and `OrthographicCameraBundle` (generic on camera marker components like Camera2d and Camera3d) have been replaced by `Camera3dBundle` and `Camera2dBundle`, which set 3d and 2d default values for the `CameraRenderGraph` and projections. ```rust // old 3d perspective camera commands.spawn_bundle(PerspectiveCameraBundle::default()) // new 3d perspective camera commands.spawn_bundle(Camera3dBundle::default()) ``` ```rust // old 2d orthographic camera commands.spawn_bundle(OrthographicCameraBundle::new_2d()) // new 2d orthographic camera commands.spawn_bundle(Camera2dBundle::default()) ``` ```rust // old 3d orthographic camera commands.spawn_bundle(OrthographicCameraBundle::new_3d()) // new 3d orthographic camera commands.spawn_bundle(Camera3dBundle { projection: OrthographicProjection { scale: 3.0, scaling_mode: ScalingMode::FixedVertical, ..default() }.into(), ..default() }) ``` Note that `Camera3dBundle` now uses a new `Projection` enum instead of hard coding the projection into the type. There are a number of motivators for this change: the render graph is now a part of the bundle, the way "generic bundles" work in the rust type system prevents nice `..default()` syntax, and changing projections at runtime is much easier with an enum (ex for editor scenarios). I'm open to discussing this choice, but I'm relatively certain we will all come to the same conclusion here. Camera2dBundle and Camera3dBundle are much clearer than being generic on marker components / using non-default constructors. If you want to run a custom render graph on a camera, just set the `CameraRenderGraph` component: ```rust commands.spawn_bundle(Camera3dBundle { camera_render_graph: CameraRenderGraph::new(some_render_graph_name), ..default() }) ``` Just note that if the graph requires data from specific components to work (such as `Camera3d` config, which is provided in the `Camera3dBundle`), make sure the relevant components have been added. Speaking of using components to configure graphs / passes, there are a number of new configuration options: ```rust commands.spawn_bundle(Camera3dBundle { camera_3d: Camera3d { // overrides the default global clear color clear_color: ClearColorConfig::Custom(Color::RED), ..default() }, ..default() }) commands.spawn_bundle(Camera3dBundle { camera_3d: Camera3d { // disables clearing clear_color: ClearColorConfig::None, ..default() }, ..default() }) ``` Expect to see more of the "graph configuration Components on Cameras" pattern in the future. By popular demand, UI no longer requires a dedicated camera. `UiCameraBundle` has been removed. `Camera2dBundle` and `Camera3dBundle` now both default to rendering UI as part of their own render graphs. To disable UI rendering for a camera, disable it using the CameraUi component: ```rust commands .spawn_bundle(Camera3dBundle::default()) .insert(CameraUi { is_enabled: false, ..default() }) ``` ## Other Changes * The separate clear pass has been removed. We should revisit this for things like sky rendering, but I think this PR should "keep it simple" until we're ready to properly support that (for code complexity and performance reasons). We can come up with the right design for a modular clear pass in a followup pr. * I reorganized bevy_core_pipeline into Core2dPlugin and Core3dPlugin (and core_2d / core_3d modules). Everything is pretty much the same as before, just logically separate. I've moved relevant types (like Camera2d, Camera3d, Camera3dBundle, Camera2dBundle) into their relevant modules, which is what motivated this reorganization. * I adapted the `scene_viewer` example (which relied on the ActiveCameras behavior) to the new system. I also refactored bits and pieces to be a bit simpler. * All of the examples have been ported to the new camera approach. `render_to_texture` and `multiple_windows` are now _much_ simpler. I removed `two_passes` because it is less relevant with the new approach. If someone wants to add a new "layered custom pass with CameraRenderGraph" example, that might fill a similar niche. But I don't feel much pressure to add that in this pr. * Cameras now have `target_logical_size` and `target_physical_size` fields, which makes finding the size of a camera's render target _much_ simpler. As a result, the `Assets<Image>` and `Windows` parameters were removed from `Camera::world_to_screen`, making that operation much more ergonomic. * Render order ambiguities between cameras with the same target and the same priority now produce a warning. This accomplishes two goals: 1. Now that there is no "global" active camera, by default spawning two cameras will result in two renders (one covering the other). This would be a silent performance killer that would be hard to detect after the fact. By detecting ambiguities, we can provide a helpful warning when this occurs. 2. Render order ambiguities could result in unexpected / unpredictable render results. Resolving them makes sense. ## Follow Up Work * Per-Camera viewports, which will make it possible to render to a smaller area inside of a RenderTarget (great for something like splitscreen) * Camera-specific MSAA config (should use the same "overriding" pattern used for ClearColor) * Graph Based Camera Ordering: priorities are simple, but they make complicated ordering constraints harder to express. We should consider adopting a "graph based" camera ordering model with "before" and "after" relationships to other cameras (or build it "on top" of the priority system). * Consider allowing graphs to run subgraphs from any nest level (aka a global namespace for graphs). Right now the 2d and 3d graphs each need their own UI subgraph, which feels "fine" in the short term. But being able to share subgraphs between other subgraphs seems valuable. * Consider splitting `bevy_core_pipeline` into `bevy_core_2d` and `bevy_core_3d` packages. Theres a shared "clear color" dependency here, which would need a new home. |
||
Thierry Berger
|
99e689cfd2 |
remove unneeded msaa explicit addition from examples (#4830)
# Objective
- Coming from
|
||
Mark Schmale
|
1ba7429371 |
Doc/module style doc blocks for examples (#4438)
# Objective Provide a starting point for #3951, or a partial solution. Providing a few comment blocks to discuss, and hopefully find better one in the process. ## Solution Since I am pretty new to pretty much anything in this context, I figured I'd just start with a draft for some file level doc blocks. For some of them I found more relevant details (or at least things I considered interessting), for some others there is less. ## Changelog - Moved some existing comments from main() functions in the 2d examples to the file header level - Wrote some more comment blocks for most other 2d examples TODO: - [x] 2d/sprite_sheet, wasnt able to come up with something good yet - [x] all other example groups... Also: Please let me know if the commit style is okay, or to verbose. I could certainly squash these things, or add more details if needed. I also hope its okay to raise this PR this early, with just a few files changed. Took me long enough and I dont wanted to let it go to waste because I lost motivation to do the whole thing. Additionally I am somewhat uncertain over the style and contents of the commets. So let me know what you thing please. |
||
Carter Anderson
|
b6a647cc01 |
default() shorthand (#4071)
Adds a `default()` shorthand for `Default::default()` ... because life is too short to constantly type `Default::default()`. ```rust use bevy::prelude::*; #[derive(Default)] struct Foo { bar: usize, baz: usize, } // Normally you would do this: let foo = Foo { bar: 10, ..Default::default() }; // But now you can do this: let foo = Foo { bar: 10, ..default() }; ``` The examples have been adapted to use `..default()`. I've left internal crates as-is for now because they don't pull in the bevy prelude, and the ergonomics of each case should be considered individually. |
||
Robert Swain
|
936468aa1e |
bevy_render: Use RenderDevice to get limits/features and expose AdapterInfo (#3931)
# Objective - `WgpuOptions` is mutated to be updated with the actual device limits and features, but this information is readily available to both the main and render worlds through the `RenderDevice` which has .limits() and .features() methods - Information about the adapter in terms of its name, the backend in use, etc were not being exposed but have clear use cases for being used to take decisions about what rendering code to use. For example, if something works well on AMD GPUs but poorly on Intel GPUs. Or perhaps something works well in Vulkan but poorly in DX12. ## Solution - Stop mutating `WgpuOptions `and don't insert the updated values into the main and render worlds - Return `AdapterInfo` from `initialize_renderer` and insert it into the main and render worlds - Use `RenderDevice` limits in the lighting code that was using `WgpuOptions.limits`. - Renamed `WgpuOptions` to `WgpuSettings` |
||
Carter Anderson
|
ffecb05a0a |
Replace old renderer with new renderer (#3312)
This makes the [New Bevy Renderer](#2535) the default (and only) renderer. The new renderer isn't _quite_ ready for the final release yet, but I want as many people as possible to start testing it so we can identify bugs and address feedback prior to release. The examples are all ported over and operational with a few exceptions: * I removed a good portion of the examples in the `shader` folder. We still have some work to do in order to make these examples possible / ergonomic / worthwhile: #3120 and "high level shader material plugins" are the big ones. This is a temporary measure. * Temporarily removed the multiple_windows example: doing this properly in the new renderer will require the upcoming "render targets" changes. Same goes for the render_to_texture example. * Removed z_sort_debug: entity visibility sort info is no longer available in app logic. we could do this on the "render app" side, but i dont consider it a priority. |
||
Carter Anderson
|
43e8a156fb |
Upgrade to wgpu 0.11 (#2933)
Upgrades both the old and new renderer to wgpu 0.11 (and naga 0.7). This builds on @zicklag's work here #2556. Co-authored-by: Carter Anderson <mcanders1@gmail.com> |
||
Carter Anderson
|
11b41206eb |
Add upstream bevy_ecs and prepare for custom-shaders merge (#2815)
This updates the `pipelined-rendering` branch to use the latest `bevy_ecs` from `main`. This accomplishes a couple of goals: 1. prepares for upcoming `custom-shaders` branch changes, which were what drove many of the recent bevy_ecs changes on `main` 2. prepares for the soon-to-happen merge of `pipelined-rendering` into `main`. By including bevy_ecs changes now, we make that merge simpler / easier to review. I split this up into 3 commits: 1. **add upstream bevy_ecs**: please don't bother reviewing this content. it has already received thorough review on `main` and is a literal copy/paste of the relevant folders (the old folders were deleted so the directories are literally exactly the same as `main`). 2. **support manual buffer application in stages**: this is used to enable the Extract step. we've already reviewed this once on the `pipelined-rendering` branch, but its worth looking at one more time in the new context of (1). 3. **support manual archetype updates in QueryState**: same situation as (2). |
||
Carter Anderson
|
4ac2ed7cc6 | pipelined rendering proof of concept | ||
Jonas Matser
|
5c4f3554f9 |
Rename Light => PointLight and remove unused properties (#1778)
After an inquiry on Reddit about support for Directional Lights and the unused properties on Light, I wanted to clean it up, to hopefully make it ever so slightly more clear for anyone wanting to add additional light types. Co-authored-by: Carter Anderson <mcanders1@gmail.com> |
||
Carter Anderson
|
81b53d15d4 |
Make Commands and World apis consistent (#1703)
Resolves #1253 #1562 This makes the Commands apis consistent with World apis. This moves to a "type state" pattern (like World) where the "current entity" is stored in an `EntityCommands` builder. In general this tends to cuts down on indentation and line count. It comes at the cost of needing to type `commands` more and adding more semicolons to terminate expressions. I also added `spawn_bundle` to Commands because this is a common enough operation that I think its worth providing a shorthand. |
||
François
|
bbb9849506 |
Replace default method calls from Glam types with explicit const (#1645)
it's a followup of #1550 I think calling explicit methods/values instead of default makes the code easier to read: "what is `Quat::default()`" vs "Oh, it's `Quat::IDENTITY`" `Transform::identity()` and `GlobalTransform::identity()` can also be consts and I replaced the calls to their `default()` impl with `identity()` |
||
MinerSebas
|
8f363544ad |
Reorder Imports in Examples (#1598)
This only affected 2 Examples: * `generic_reflection`: For some reason, a `pub use` statement was used. This was removed, and alphabetically ordered. * `wireframe`: This example used the `bevy_internal` crate directly. Changed to use `bevy` instead. All other Example Imports are correct. One potential subjective change is the `removel_detection` example. Unlike all other Examples, it has its (first) explanatory comment before the Imports. |
||
Cameron Hart
|
f61e44db28 |
Update glam to 0.13.0. (#1550)
See https://github.com/bitshifter/glam-rs/blob/master/CHANGELOG.md for details on changes. Co-authored-by: Cameron Hart <c_hart@wargaming.net> |
||
Carter Anderson
|
3a2a68852c |
Bevy ECS V2 (#1525)
# Bevy ECS V2 This is a rewrite of Bevy ECS (basically everything but the new executor/schedule, which are already awesome). The overall goal was to improve the performance and versatility of Bevy ECS. Here is a quick bulleted list of changes before we dive into the details: * Complete World rewrite * Multiple component storage types: * Tables: fast cache friendly iteration, slower add/removes (previously called Archetypes) * Sparse Sets: fast add/remove, slower iteration * Stateful Queries (caches query results for faster iteration. fragmented iteration is _fast_ now) * Stateful System Params (caches expensive operations. inspired by @DJMcNab's work in #1364) * Configurable System Params (users can set configuration when they construct their systems. once again inspired by @DJMcNab's work) * Archetypes are now "just metadata", component storage is separate * Archetype Graph (for faster archetype changes) * Component Metadata * Configure component storage type * Retrieve information about component size/type/name/layout/send-ness/etc * Components are uniquely identified by a densely packed ComponentId * TypeIds are now totally optional (which should make implementing scripting easier) * Super fast "for_each" query iterators * Merged Resources into World. Resources are now just a special type of component * EntityRef/EntityMut builder apis (more efficient and more ergonomic) * Fast bitset-backed `Access<T>` replaces old hashmap-based approach everywhere * Query conflicts are determined by component access instead of archetype component access (to avoid random failures at runtime) * With/Without are still taken into account for conflicts, so this should still be comfy to use * Much simpler `IntoSystem` impl * Significantly reduced the amount of hashing throughout the ecs in favor of Sparse Sets (indexed by densely packed ArchetypeId, ComponentId, BundleId, and TableId) * Safety Improvements * Entity reservation uses a normal world reference instead of unsafe transmute * QuerySets no longer transmute lifetimes * Made traits "unsafe" where relevant * More thorough safety docs * WorldCell * Exposes safe mutable access to multiple resources at a time in a World * Replaced "catch all" `System::update_archetypes(world: &World)` with `System::new_archetype(archetype: &Archetype)` * Simpler Bundle implementation * Replaced slow "remove_bundle_one_by_one" used as fallback for Commands::remove_bundle with fast "remove_bundle_intersection" * Removed `Mut<T>` query impl. it is better to only support one way: `&mut T` * Removed with() from `Flags<T>` in favor of `Option<Flags<T>>`, which allows querying for flags to be "filtered" by default * Components now have is_send property (currently only resources support non-send) * More granular module organization * New `RemovedComponents<T>` SystemParam that replaces `query.removed::<T>()` * `world.resource_scope()` for mutable access to resources and world at the same time * WorldQuery and QueryFilter traits unified. FilterFetch trait added to enable "short circuit" filtering. Auto impled for cases that don't need it * Significantly slimmed down SystemState in favor of individual SystemParam state * System Commands changed from `commands: &mut Commands` back to `mut commands: Commands` (to allow Commands to have a World reference) Fixes #1320 ## `World` Rewrite This is a from-scratch rewrite of `World` that fills the niche that `hecs` used to. Yes, this means Bevy ECS is no longer a "fork" of hecs. We're going out our own! (the only shared code between the projects is the entity id allocator, which is already basically ideal) A huge shout out to @SanderMertens (author of [flecs](https://github.com/SanderMertens/flecs)) for sharing some great ideas with me (specifically hybrid ecs storage and archetype graphs). He also helped advise on a number of implementation details. ## Component Storage (The Problem) Two ECS storage paradigms have gained a lot of traction over the years: * **Archetypal ECS**: * Stores components in "tables" with static schemas. Each "column" stores components of a given type. Each "row" is an entity. * Each "archetype" has its own table. Adding/removing an entity's component changes the archetype. * Enables super-fast Query iteration due to its cache-friendly data layout * Comes at the cost of more expensive add/remove operations for an Entity's components, because all components need to be copied to the new archetype's "table" * **Sparse Set ECS**: * Stores components of the same type in densely packed arrays, which are sparsely indexed by densely packed unsigned integers (Entity ids) * Query iteration is slower than Archetypal ECS because each entity's component could be at any position in the sparse set. This "random access" pattern isn't cache friendly. Additionally, there is an extra layer of indirection because you must first map the entity id to an index in the component array. * Adding/removing components is a cheap, constant time operation Bevy ECS V1, hecs, legion, flec, and Unity DOTS are all "archetypal ecs-es". I personally think "archetypal" storage is a good default for game engines. An entity's archetype doesn't need to change frequently in general, and it creates "fast by default" query iteration (which is a much more common operation). It is also "self optimizing". Users don't need to think about optimizing component layouts for iteration performance. It "just works" without any extra boilerplate. Shipyard and EnTT are "sparse set ecs-es". They employ "packing" as a way to work around the "suboptimal by default" iteration performance for specific sets of components. This helps, but I didn't think this was a good choice for a general purpose engine like Bevy because: 1. "packs" conflict with each other. If bevy decides to internally pack the Transform and GlobalTransform components, users are then blocked if they want to pack some custom component with Transform. 2. users need to take manual action to optimize Developers selecting an ECS framework are stuck with a hard choice. Select an "archetypal" framework with "fast iteration everywhere" but without the ability to cheaply add/remove components, or select a "sparse set" framework to cheaply add/remove components but with slower iteration performance. ## Hybrid Component Storage (The Solution) In Bevy ECS V2, we get to have our cake and eat it too. It now has _both_ of the component storage types above (and more can be added later if needed): * **Tables** (aka "archetypal" storage) * The default storage. If you don't configure anything, this is what you get * Fast iteration by default * Slower add/remove operations * **Sparse Sets** * Opt-in * Slower iteration * Faster add/remove operations These storage types complement each other perfectly. By default Query iteration is fast. If developers know that they want to add/remove a component at high frequencies, they can set the storage to "sparse set": ```rust world.register_component( ComponentDescriptor:🆕:<MyComponent>(StorageType::SparseSet) ).unwrap(); ``` ## Archetypes Archetypes are now "just metadata" ... they no longer store components directly. They do store: * The `ComponentId`s of each of the Archetype's components (and that component's storage type) * Archetypes are uniquely defined by their component layouts * For example: entities with "table" components `[A, B, C]` _and_ "sparse set" components `[D, E]` will always be in the same archetype. * The `TableId` associated with the archetype * For now each archetype has exactly one table (which can have no components), * There is a 1->Many relationship from Tables->Archetypes. A given table could have any number of archetype components stored in it: * Ex: an entity with "table storage" components `[A, B, C]` and "sparse set" components `[D, E]` will share the same `[A, B, C]` table as an entity with `[A, B, C]` table component and `[F]` sparse set components. * This 1->Many relationship is how we preserve fast "cache friendly" iteration performance when possible (more on this later) * A list of entities that are in the archetype and the row id of the table they are in * ArchetypeComponentIds * unique densely packed identifiers for (ArchetypeId, ComponentId) pairs * used by the schedule executor for cheap system access control * "Archetype Graph Edges" (see the next section) ## The "Archetype Graph" Archetype changes in Bevy (and a number of other archetypal ecs-es) have historically been expensive to compute. First, you need to allocate a new vector of the entity's current component ids, add or remove components based on the operation performed, sort it (to ensure it is order-independent), then hash it to find the archetype (if it exists). And thats all before we get to the _already_ expensive full copy of all components to the new table storage. The solution is to build a "graph" of archetypes to cache these results. @SanderMertens first exposed me to the idea (and he got it from @gjroelofs, who came up with it). They propose adding directed edges between archetypes for add/remove component operations. If `ComponentId`s are densely packed, you can use sparse sets to cheaply jump between archetypes. Bevy takes this one step further by using add/remove `Bundle` edges instead of `Component` edges. Bevy encourages the use of `Bundles` to group add/remove operations. This is largely for "clearer game logic" reasons, but it also helps cut down on the number of archetype changes required. `Bundles` now also have densely-packed `BundleId`s. This allows us to use a _single_ edge for each bundle operation (rather than needing to traverse N edges ... one for each component). Single component operations are also bundles, so this is strictly an improvement over a "component only" graph. As a result, an operation that used to be _heavy_ (both for allocations and compute) is now two dirt-cheap array lookups and zero allocations. ## Stateful Queries World queries are now stateful. This allows us to: 1. Cache archetype (and table) matches * This resolves another issue with (naive) archetypal ECS: query performance getting worse as the number of archetypes goes up (and fragmentation occurs). 2. Cache Fetch and Filter state * The expensive parts of fetch/filter operations (such as hashing the TypeId to find the ComponentId) now only happen once when the Query is first constructed 3. Incrementally build up state * When new archetypes are added, we only process the new archetypes (no need to rebuild state for old archetypes) As a result, the direct `World` query api now looks like this: ```rust let mut query = world.query::<(&A, &mut B)>(); for (a, mut b) in query.iter_mut(&mut world) { } ``` Requiring `World` to generate stateful queries (rather than letting the `QueryState` type be constructed separately) allows us to ensure that _all_ queries are properly initialized (and the relevant world state, such as ComponentIds). This enables QueryState to remove branches from its operations that check for initialization status (and also enables query.iter() to take an immutable world reference because it doesn't need to initialize anything in world). However in systems, this is a non-breaking change. State management is done internally by the relevant SystemParam. ## Stateful SystemParams Like Queries, `SystemParams` now also cache state. For example, `Query` system params store the "stateful query" state mentioned above. Commands store their internal `CommandQueue`. This means you can now safely use as many separate `Commands` parameters in your system as you want. `Local<T>` system params store their `T` value in their state (instead of in Resources). SystemParam state also enabled a significant slim-down of SystemState. It is much nicer to look at now. Per-SystemParam state naturally insulates us from an "aliased mut" class of errors we have hit in the past (ex: using multiple `Commands` system params). (credit goes to @DJMcNab for the initial idea and draft pr here #1364) ## Configurable SystemParams @DJMcNab also had the great idea to make SystemParams configurable. This allows users to provide some initial configuration / values for system parameters (when possible). Most SystemParams have no config (the config type is `()`), but the `Local<T>` param now supports user-provided parameters: ```rust fn foo(value: Local<usize>) { } app.add_system(foo.system().config(|c| c.0 = Some(10))); ``` ## Uber Fast "for_each" Query Iterators Developers now have the choice to use a fast "for_each" iterator, which yields ~1.5-3x iteration speed improvements for "fragmented iteration", and minor ~1.2x iteration speed improvements for unfragmented iteration. ```rust fn system(query: Query<(&A, &mut B)>) { // you now have the option to do this for a speed boost query.for_each_mut(|(a, mut b)| { }); // however normal iterators are still available for (a, mut b) in query.iter_mut() { } } ``` I think in most cases we should continue to encourage "normal" iterators as they are more flexible and more "rust idiomatic". But when that extra "oomf" is needed, it makes sense to use `for_each`. We should also consider using `for_each` for internal bevy systems to give our users a nice speed boost (but that should be a separate pr). ## Component Metadata `World` now has a `Components` collection, which is accessible via `world.components()`. This stores mappings from `ComponentId` to `ComponentInfo`, as well as `TypeId` to `ComponentId` mappings (where relevant). `ComponentInfo` stores information about the component, such as ComponentId, TypeId, memory layout, send-ness (currently limited to resources), and storage type. ## Significantly Cheaper `Access<T>` We used to use `TypeAccess<TypeId>` to manage read/write component/archetype-component access. This was expensive because TypeIds must be hashed and compared individually. The parallel executor got around this by "condensing" type ids into bitset-backed access types. This worked, but it had to be re-generated from the `TypeAccess<TypeId>`sources every time archetypes changed. This pr removes TypeAccess in favor of faster bitset access everywhere. We can do this thanks to the move to densely packed `ComponentId`s and `ArchetypeComponentId`s. ## Merged Resources into World Resources had a lot of redundant functionality with Components. They stored typed data, they had access control, they had unique ids, they were queryable via SystemParams, etc. In fact the _only_ major difference between them was that they were unique (and didn't correlate to an entity). Separate resources also had the downside of requiring a separate set of access controls, which meant the parallel executor needed to compare more bitsets per system and manage more state. I initially got the "separate resources" idea from `legion`. I think that design was motivated by the fact that it made the direct world query/resource lifetime interactions more manageable. It certainly made our lives easier when using Resources alongside hecs/bevy_ecs. However we already have a construct for safely and ergonomically managing in-world lifetimes: systems (which use `Access<T>` internally). This pr merges Resources into World: ```rust world.insert_resource(1); world.insert_resource(2.0); let a = world.get_resource::<i32>().unwrap(); let mut b = world.get_resource_mut::<f64>().unwrap(); *b = 3.0; ``` Resources are now just a special kind of component. They have their own ComponentIds (and their own resource TypeId->ComponentId scope, so they don't conflict wit components of the same type). They are stored in a special "resource archetype", which stores components inside the archetype using a new `unique_components` sparse set (note that this sparse set could later be used to implement Tags). This allows us to keep the code size small by reusing existing datastructures (namely Column, Archetype, ComponentFlags, and ComponentInfo). This allows us the executor to use a single `Access<ArchetypeComponentId>` per system. It should also make scripting language integration easier. _But_ this merge did create problems for people directly interacting with `World`. What if you need mutable access to multiple resources at the same time? `world.get_resource_mut()` borrows World mutably! ## WorldCell WorldCell applies the `Access<ArchetypeComponentId>` concept to direct world access: ```rust let world_cell = world.cell(); let a = world_cell.get_resource_mut::<i32>().unwrap(); let b = world_cell.get_resource_mut::<f64>().unwrap(); ``` This adds cheap runtime checks (a sparse set lookup of `ArchetypeComponentId` and a counter) to ensure that world accesses do not conflict with each other. Each operation returns a `WorldBorrow<'w, T>` or `WorldBorrowMut<'w, T>` wrapper type, which will release the relevant ArchetypeComponentId resources when dropped. World caches the access sparse set (and only one cell can exist at a time), so `world.cell()` is a cheap operation. WorldCell does _not_ use atomic operations. It is non-send, does a mutable borrow of world to prevent other accesses, and uses a simple `Rc<RefCell<ArchetypeComponentAccess>>` wrapper in each WorldBorrow pointer. The api is currently limited to resource access, but it can and should be extended to queries / entity component access. ## Resource Scopes WorldCell does not yet support component queries, and even when it does there are sometimes legitimate reasons to want a mutable world ref _and_ a mutable resource ref (ex: bevy_render and bevy_scene both need this). In these cases we could always drop down to the unsafe `world.get_resource_unchecked_mut()`, but that is not ideal! Instead developers can use a "resource scope" ```rust world.resource_scope(|world: &mut World, a: &mut A| { }) ``` This temporarily removes the `A` resource from `World`, provides mutable pointers to both, and re-adds A to World when finished. Thanks to the move to ComponentIds/sparse sets, this is a cheap operation. If multiple resources are required, scopes can be nested. We could also consider adding a "resource tuple" to the api if this pattern becomes common and the boilerplate gets nasty. ## Query Conflicts Use ComponentId Instead of ArchetypeComponentId For safety reasons, systems cannot contain queries that conflict with each other without wrapping them in a QuerySet. On bevy `main`, we use ArchetypeComponentIds to determine conflicts. This is nice because it can take into account filters: ```rust // these queries will never conflict due to their filters fn filter_system(a: Query<&mut A, With<B>>, b: Query<&mut B, Without<B>>) { } ``` But it also has a significant downside: ```rust // these queries will not conflict _until_ an entity with A, B, and C is spawned fn maybe_conflicts_system(a: Query<(&mut A, &C)>, b: Query<(&mut A, &B)>) { } ``` The system above will panic at runtime if an entity with A, B, and C is spawned. This makes it hard to trust that your game logic will run without crashing. In this pr, I switched to using `ComponentId` instead. This _is_ more constraining. `maybe_conflicts_system` will now always fail, but it will do it consistently at startup. Naively, it would also _disallow_ `filter_system`, which would be a significant downgrade in usability. Bevy has a number of internal systems that rely on disjoint queries and I expect it to be a common pattern in userspace. To resolve this, I added a new `FilteredAccess<T>` type, which wraps `Access<T>` and adds with/without filters. If two `FilteredAccess` have with/without values that prove they are disjoint, they will no longer conflict. ## EntityRef / EntityMut World entity operations on `main` require that the user passes in an `entity` id to each operation: ```rust let entity = world.spawn((A, )); // create a new entity with A world.get::<A>(entity); world.insert(entity, (B, C)); world.insert_one(entity, D); ``` This means that each operation needs to look up the entity location / verify its validity. The initial spawn operation also requires a Bundle as input. This can be awkward when no components are required (or one component is required). These operations have been replaced by `EntityRef` and `EntityMut`, which are "builder-style" wrappers around world that provide read and read/write operations on a single, pre-validated entity: ```rust // spawn now takes no inputs and returns an EntityMut let entity = world.spawn() .insert(A) // insert a single component into the entity .insert_bundle((B, C)) // insert a bundle of components into the entity .id() // id returns the Entity id // Returns EntityMut (or panics if the entity does not exist) world.entity_mut(entity) .insert(D) .insert_bundle(SomeBundle::default()); { // returns EntityRef (or panics if the entity does not exist) let d = world.entity(entity) .get::<D>() // gets the D component .unwrap(); // world.get still exists for ergonomics let d = world.get::<D>(entity).unwrap(); } // These variants return Options if you want to check existence instead of panicing world.get_entity_mut(entity) .unwrap() .insert(E); if let Some(entity_ref) = world.get_entity(entity) { let d = entity_ref.get::<D>().unwrap(); } ``` This _does not_ affect the current Commands api or terminology. I think that should be a separate conversation as that is a much larger breaking change. ## Safety Improvements * Entity reservation in Commands uses a normal world borrow instead of an unsafe transmute * QuerySets no longer transmutes lifetimes * Made traits "unsafe" when implementing a trait incorrectly could cause unsafety * More thorough safety docs ## RemovedComponents SystemParam The old approach to querying removed components: `query.removed:<T>()` was confusing because it had no connection to the query itself. I replaced it with the following, which is both clearer and allows us to cache the ComponentId mapping in the SystemParamState: ```rust fn system(removed: RemovedComponents<T>) { for entity in removed.iter() { } } ``` ## Simpler Bundle implementation Bundles are no longer responsible for sorting (or deduping) TypeInfo. They are just a simple ordered list of component types / data. This makes the implementation smaller and opens the door to an easy "nested bundle" implementation in the future (which i might even add in this pr). Duplicate detection is now done once per bundle type by World the first time a bundle is used. ## Unified WorldQuery and QueryFilter types (don't worry they are still separate type _parameters_ in Queries .. this is a non-breaking change) WorldQuery and QueryFilter were already basically identical apis. With the addition of `FetchState` and more storage-specific fetch methods, the overlap was even clearer (and the redundancy more painful). QueryFilters are now just `F: WorldQuery where F::Fetch: FilterFetch`. FilterFetch requires `Fetch<Item = bool>` and adds new "short circuit" variants of fetch methods. This enables a filter tuple like `(With<A>, Without<B>, Changed<C>)` to stop evaluating the filter after the first mismatch is encountered. FilterFetch is automatically implemented for `Fetch` implementations that return bool. This forces fetch implementations that return things like `(bool, bool, bool)` (such as the filter above) to manually implement FilterFetch and decide whether or not to short-circuit. ## More Granular Modules World no longer globs all of the internal modules together. It now exports `core`, `system`, and `schedule` separately. I'm also considering exporting `core` submodules directly as that is still pretty "glob-ey" and unorganized (feedback welcome here). ## Remaining Draft Work (to be done in this pr) * ~~panic on conflicting WorldQuery fetches (&A, &mut A)~~ * ~~bevy `main` and hecs both currently allow this, but we should protect against it if possible~~ * ~~batch_iter / par_iter (currently stubbed out)~~ * ~~ChangedRes~~ * ~~I skipped this while we sort out #1313. This pr should be adapted to account for whatever we land on there~~. * ~~The `Archetypes` and `Tables` collections use hashes of sorted lists of component ids to uniquely identify each archetype/table. This hash is then used as the key in a HashMap to look up the relevant ArchetypeId or TableId. (which doesn't handle hash collisions properly)~~ * ~~It is currently unsafe to generate a Query from "World A", then use it on "World B" (despite the api claiming it is safe). We should probably close this gap. This could be done by adding a randomly generated WorldId to each world, then storing that id in each Query. They could then be compared to each other on each `query.do_thing(&world)` operation. This _does_ add an extra branch to each query operation, so I'm open to other suggestions if people have them.~~ * ~~Nested Bundles (if i find time)~~ ## Potential Future Work * Expand WorldCell to support queries. * Consider not allocating in the empty archetype on `world.spawn()` * ex: return something like EntityMutUninit, which turns into EntityMut after an `insert` or `insert_bundle` op * this actually regressed performance last time i tried it, but in theory it should be faster * Optimize SparseSet::insert (see `PERF` comment on insert) * Replace SparseArray `Option<T>` with T::MAX to cut down on branching * would enable cheaper get_unchecked() operations * upstream fixedbitset optimizations * fixedbitset could be allocation free for small block counts (store blocks in a SmallVec) * fixedbitset could have a const constructor * Consider implementing Tags (archetype-specific by-value data that affects archetype identity) * ex: ArchetypeA could have `[A, B, C]` table components and `[D(1)]` "tag" component. ArchetypeB could have `[A, B, C]` table components and a `[D(2)]` tag component. The archetypes are different, despite both having D tags because the value inside D is different. * this could potentially build on top of the `archetype.unique_components` added in this pr for resource storage. * Consider reverting `all_tuples` proc macro in favor of the old `macro_rules` implementation * all_tuples is more flexible and produces cleaner documentation (the macro_rules version produces weird type parameter orders due to parser constraints) * but unfortunately all_tuples also appears to make Rust Analyzer sad/slow when working inside of `bevy_ecs` (does not affect user code) * Consider "resource queries" and/or "mixed resource and entity component queries" as an alternative to WorldCell * this is basically just "systems" so maybe it's not worth it * Add more world ops * `world.clear()` * `world.reserve<T: Bundle>(count: usize)` * Try using the old archetype allocation strategy (allocate new memory on resize and copy everything over). I expect this to improve batch insertion performance at the cost of unbatched performance. But thats just a guess. I'm not an allocation perf pro :) * Adapt Commands apis for consistency with new World apis ## Benchmarks key: * `bevy_old`: bevy `main` branch * `bevy`: this branch * `_foreach`: uses an optimized for_each iterator * ` _sparse`: uses sparse set storage (if unspecified assume table storage) * `_system`: runs inside a system (if unspecified assume test happens via direct world ops) ### Simple Insert (from ecs_bench_suite) ![image](https://user-images.githubusercontent.com/2694663/109245573-9c3ce100-7795-11eb-9003-bfd41cd5c51f.png) ### Simpler Iter (from ecs_bench_suite) ![image](https://user-images.githubusercontent.com/2694663/109245795-ffc70e80-7795-11eb-92fb-3ffad09aabf7.png) ### Fragment Iter (from ecs_bench_suite) ![image](https://user-images.githubusercontent.com/2694663/109245849-0fdeee00-7796-11eb-8d25-eb6b7a682c48.png) ### Sparse Fragmented Iter Iterate a query that matches 5 entities from a single matching archetype, but there are 100 unmatching archetypes ![image](https://user-images.githubusercontent.com/2694663/109245916-2b49f900-7796-11eb-9a8f-ed89c203f940.png) ### Schedule (from ecs_bench_suite) ![image](https://user-images.githubusercontent.com/2694663/109246428-1fab0200-7797-11eb-8841-1b2161e90fa4.png) ### Add Remove Component (from ecs_bench_suite) ![image](https://user-images.githubusercontent.com/2694663/109246492-39e4e000-7797-11eb-8985-2706bd0495ab.png) ### Add Remove Component Big Same as the test above, but each entity has 5 "large" matrix components and 1 "large" matrix component is added and removed ![image](https://user-images.githubusercontent.com/2694663/109246517-449f7500-7797-11eb-835e-28b6790daeaa.png) ### Get Component Looks up a single component value a large number of times ![image](https://user-images.githubusercontent.com/2694663/109246129-87ad1880-7796-11eb-9fcb-c38012aa7c70.png) |
||
Zhixing Zhang
|
d9fb61d474 |
Wireframe Rendering Pipeline (#562)
This PR implements wireframe rendering. Usage: This is now ready as soon as #1401 gets merged. Usage: ```rust app .insert_resource(WgpuOptions { name: Some("3d_scene"), features: WgpuFeatures::NON_FILL_POLYGON_MODE, ..Default::default() }) // To enable the NON_FILL_POLYGON_MODE feature .add_plugin(WireframePlugin) .run(); ``` Now we just need to add the Wireframe component on an entity, and it'll draw. its wireframe. We can also enable wireframe drawing globally by setting the global property in the `WireframeConfig` resource to `true`. Co-authored-by: Zhixing Zhang <me@neoto.xin> |