Commit graph

587 commits

Author SHA1 Message Date
Aevyrie
915fa69b66 Parallel Frustum Culling (#4489)
# Objective

Working with a large number of entities with `Aabbs`, rendered with an instanced shader, I found the bottleneck became the frustum culling system. The goal of this PR is to significantly improve culling performance without any major changes. We should consider constructing a BVH for more substantial improvements.

## Solution

- Convert the inner entity query to a parallel iterator with `par_for_each_mut` using a batch size of 1,024. 
- This outperforms single threaded culling when there are more than 1,000 entities. 
  - Below this they are approximately equal, with <= 10 microseconds of multithreading overhead.
  - Above this, the multithreaded version is significantly faster, scaling linearly with core count.
- In my million-entity-workload, this PR improves my framerate by 200% - 300%.

## log-log of `check_visibility` time vs. entities for single/multithreaded
![image](https://user-images.githubusercontent.com/2632925/163709007-7eab4437-e9f9-4c06-bac0-250073885110.png)

---

## Changelog

Frustum culling is now run with a parallel query. When culling more than a thousand entities, this is faster than the previous method, scaling proportionally with the number of available cores.
2022-06-14 02:07:40 +00:00
François
f969c62f7b Fix wasm examples (#4967)
# Objective

Fix #4958 

There was 4 issues:

- this is not true in WASM and on macOS: f28b921209/examples/3d/split_screen.rs (L90)
  - ~~I made sure the system was running at least once~~
  - I'm sending the event on window creation
- in webgl, setting a viewport has impacts on other render passes
  - only in webgl and when there is a custom viewport, I added a render pass without a custom viewport
- shaderdef NO_ARRAY_TEXTURES_SUPPORT was not used by the 2d pipeline
  - webgl feature was used but not declared in bevy_sprite, I added it to the Cargo.toml
- shaderdef NO_STORAGE_BUFFERS_SUPPORT was not used by the 2d pipeline
  - I added it based on the BufferBindingType

The last commit changes the two last fixes to add the shaderdefs in the shader cache directly instead of needing to do it in each pipeline

Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2022-06-11 20:10:13 +00:00
Aevyrie
772d15238c Change default Image FilterMode to Linear (#4465)
# Objective

- Closes #4464 

## Solution

- Specify default mag and min filter types for `Image` instead of using `wgpu`'s defaults.

---

## Changelog

### Changed

- Default `Image` filtering changed from `Nearest` to `Linear`.


Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2022-06-11 09:13:37 +00:00
James Liu
f2b545049c Implement FusedIterator for eligible Iterator types (#4942)
# Objective
Most of our `Iterator` impls satisfy the requirements of `std::iter::FusedIterator`, which has internal specialization that optimizes `Interator::fuse`. The std lib iterator combinators do have a few that rely on `fuse`, so this could optimize those use cases. I don't think we're using any of them in the engine itself, but beyond a light increase in compile time, it doesn't hurt to implement the trait.

## Solution
Implement the trait for all eligible iterators in first party crates. Also add a missing `ExactSizeIterator` on an iterator that could use it.
2022-06-09 03:19:31 +00:00
Aevyrie
cbf032419d Refactor Camera methods and add viewport rect (#4948)
While working on a refactor of `bevy_mod_picking` to include viewport-awareness, I found myself writing these functions to test if a cursor coordinate was inside the camera's rendered area.

# Objective

- Simplify conversion from physical to logical pixels
- Add methods that returns the dimensions of the viewport as a min-max rect

---

## Changelog

- Added `Camera::to_logical`
- Added `Camera::physical_viewport_rect`
- Added `Camera::logical_viewport_rect`
2022-06-07 15:23:45 +00:00
dataphract
b47291264b diagnostics: meaningful error when graph node has wrong number of inputs (#4924)
# Objective

Currently, providing the wrong number of inputs to a render graph node triggers this assertion:

```
thread 'main' panicked at 'assertion failed: `(left == right)`
  left: `1`,
 right: `2`', /[redacted]/bevy/crates/bevy_render/src/renderer/graph_runner.rs:164:13
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
```

This does not provide the user any context.

## Solution

Add a new `RenderGraphRunnerError` variant to handle this case. The new message looks like this:

```
ERROR bevy_render::renderer: Error running render graph:
ERROR bevy_render::renderer: > node (name: 'Some("outline_pass")') has 2 input slots, but was provided 1 values
```

---

## Changelog

### Changed

`RenderGraphRunnerError` now has a new variant, `MismatchedInputCount`.

## Migration Guide

Exhaustive matches on `RenderGraphRunnerError` will need to add a branch to handle the new `MismatchedInputCount` variant.
2022-06-06 15:47:52 +00:00
Carter Anderson
5e2cfb2f19 Camera Driven Viewports (#4898)
# Objective

Users should be able to render cameras to specific areas of a render target, which enables scenarios like split screen, minimaps, etc.

Builds on the new Camera Driven Rendering added here: #4745 
Fixes: #202
Alternative to #1389 and #3626 (which are incompatible with the new Camera Driven Rendering)

## Solution

![image](https://user-images.githubusercontent.com/2694663/171560044-f0694f67-0cd9-4598-83e2-a9658c4fed57.png)


Cameras can now configure an optional "viewport", which defines a rectangle within their render target to draw to. If a `Viewport` is defined, the camera's `CameraProjection`, `View`, and visibility calculations will use the viewport configuration instead of the full render target. 

```rust
// This camera will render to the first half of the primary window (on the left side).
commands.spawn_bundle(Camera3dBundle {
    camera: Camera {
        viewport: Some(Viewport {
            physical_position: UVec2::new(0, 0),
            physical_size: UVec2::new(window.physical_width() / 2, window.physical_height()),
            depth: 0.0..1.0,
        }),
        ..default()
    },
    ..default()
});
```

To account for this, the `Camera` component has received a few adjustments:

* `Camera` now has some new getter functions:
  * `logical_viewport_size`, `physical_viewport_size`, `logical_target_size`, `physical_target_size`, `projection_matrix`
*  All computed camera values are now private and live on the `ComputedCameraValues` field (logical/physical width/height, the projection matrix). They are now exposed on `Camera` via getters/setters  This wasn't _needed_ for viewports, but it was long overdue.

---

## Changelog

### Added

* `Camera` components now have a `viewport` field, which can be set to draw to a portion of a render target instead of the full target.
* `Camera` component has some new functions: `logical_viewport_size`, `physical_viewport_size`, `logical_target_size`, `physical_target_size`, and `projection_matrix`
* Added a new split_screen example illustrating how to render two cameras to the same scene

## Migration Guide

`Camera::projection_matrix` is no longer a public field. Use the new `Camera::projection_matrix()` method instead:

```rust

// Bevy 0.7
let projection = camera.projection_matrix;

// Bevy 0.8
let projection = camera.projection_matrix();
```
2022-06-05 00:27:49 +00:00
Matthias Deiml
1fcb7d0c2e Set naga capabilities corresponding to wgpu features (#4824)
# Objective

At the moment all extra capabilities are disabled when validating shaders with naga:
c7c08f95cb/crates/bevy_render/src/render_resource/shader.rs (L146-L149)
This means these features can't be used even if the corresponding wgpu features are active.

## Solution

With these changes capabilities are now set corresponding to `RenderDevice::features`.

---

I have validated these changes for push constants with a project I am currently working on. Though bevy does not support creating pipelines with push constants yet, so I was only able to see that shaders are validated and compiled as expected.
2022-06-03 20:50:50 +00:00
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.
2022-06-02 00:12:17 +00:00
Robert Swain
bdef86ea6e Generate vertex tangents using mikktspace (#3872)
# Objective

Models can be produced that do not have vertex tangents but do have normal map textures. The tangents can be generated. There is a way that the vertex tangents can be generated to be exactly invertible to avoid introducing error when recreating the normals in the fragment shader.

## Solution

- After attempts to get https://github.com/gltf-rs/mikktspace to integrate simple glam changes and version bumps, and releases of that crate taking weeks / not being made (no offense intended to the authors/maintainers, bevy just has its own timelines and needs to take care of) it was decided to fork that repository. The following steps were taken:
  - mikktspace was forked to https://github.com/bevyengine/mikktspace in order to preserve the repository's history in case the original is ever taken down
  - The README in that repo was edited to add a note stating from where the repository was forked and explaining why
  - The repo was locked for changes as its only purpose is historical
  - The repo was integrated into the bevy repo using `git subtree add --prefix crates/bevy_mikktspace git@github.com:bevyengine/mikktspace.git master`
  - In `bevy_mikktspace`:
    - The travis configuration was removed
    - `cargo fmt` was run
    - The `Cargo.toml` was conformed to bevy's (just adding bevy to the keywords, changing the homepage and repository, changing the version to 0.7.0-dev - importantly the license is exactly the same)
    - Remove the features, remove `nalgebra` entirely, only use `glam`, suppress clippy.
      - This was necessary because our CI runs clippy with `--all-features` and the `nalgebra` and `glam` features are mutually exclusive, plus I don't want to modify this highly numerically-sensitive code just to appease clippy and diverge even more from upstream.
- Rebase https://github.com/bevyengine/bevy/pull/1795
  - @jakobhellermann said it was fine to copy and paste but it ended up being almost exactly the same with just a couple of adjustments when validating correctness so I decided to actually rebase it and then build on top of it.
- Use the exact same fragment shader code to ensure correct normal mapping.
- Tested with both https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/NormalTangentMirrorTest which has vertex tangents and https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/NormalTangentTest which requires vertex tangent generation

Co-authored-by: alteous <alteous@outlook.com>
2022-05-31 22:53:54 +00:00
Daniikk1012
ae0ccfb4f6 Make ScalingMode more flexible (#3253)
Adds ability to specify scaling factor for `WindowSize`, size of the fixed axis for `FixedVertical` and `FixedHorizontal` and a new `ScalingMode` that is a mix of `FixedVertical` and `FixedHorizontal`

# The issue

Currently, only available options are to:

* Have one of the axes fixed to value 1
* Have viewport size match the window size
* Manually adjust viewport size

In most of the games these options are not enough and more advanced scaling methods have to be used

## Solution

The solution is to provide additional parameters to current scaling modes, like scaling factor for `WindowSize`. Additionally, a more advanced `Auto` mode is added, which dynamically switches between behaving like `FixedVertical` and `FixedHorizontal` depending on the window's aspect ratio.

Co-authored-by: Daniikk1012 <49123959+Daniikk1012@users.noreply.github.com>
2022-05-31 17:14:12 +00:00
Félix Lescaudey de Maneville
f000c2b951 Clippy improvements (#4665)
# Objective

Follow up to my previous MR #3718 to add new clippy warnings to bevy:

- [x] [~~option_if_let_else~~](https://rust-lang.github.io/rust-clippy/master/#option_if_let_else) (reverted)
- [x] [redundant_else](https://rust-lang.github.io/rust-clippy/master/#redundant_else)
- [x] [match_same_arms](https://rust-lang.github.io/rust-clippy/master/#match_same_arms)
- [x] [semicolon_if_nothing_returned](https://rust-lang.github.io/rust-clippy/master/#semicolon_if_nothing_returned)
- [x] [explicit_iter_loop](https://rust-lang.github.io/rust-clippy/master/#explicit_iter_loop)
- [x] [map_flatten](https://rust-lang.github.io/rust-clippy/master/#map_flatten)

There is one commit per clippy warning, and the matching flags are added to the CI execution.

To test the CI execution you may run `cargo run -p ci -- clippy` at the root.

I choose the add the flags in the `ci` tool crate to avoid having them in every `lib.rs` but I guess it could become an issue with suprise warnings coming up after a commit/push


Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2022-05-31 01:38:07 +00:00
Robert Swain
a0a3d8798b ExtractResourcePlugin (#3745)
# Objective

- Add an `ExtractResourcePlugin` for convenience and consistency

## Solution

- Add an `ExtractResourcePlugin` similar to `ExtractComponentPlugin` but for ECS `Resource`s. The system that is executed simply clones the main world resource into a render world resource, if and only if the main world resource was either added or changed since the last execution of the system.
- Add an `ExtractResource` trait with a `fn extract_resource(res: &Self) -> Self` function. This is used by the `ExtractResourcePlugin` to extract the resource
- Add a derive macro for `ExtractResource` on a `Resource` with the `Clone` trait, that simply returns `res.clone()`
- Use `ExtractResourcePlugin` wherever both possible and appropriate
2022-05-30 18:36:03 +00:00
Johan Klokkhammer Helsing
aa183ef31a Derive thiserror::Error for HexColorError (again) (#4847)
This was first done in 7b4e3a5, but was then reverted when the new
renderer for 0.6 was merged (ffecb05).

I'm assuming it was simply a mistake when merging.

# Objective

- Same as #2740, I think it was reverted by mistake when merging.

> # Objective
>
> - Make it easy to use HexColorError with `thiserror`, i.e. converting it into other error types.
> 
> Makes this possible:
> 
> ```rust
> #[derive(Debug, thiserror::Error)]
> pub enum LdtkError {
>     #[error("An error occured while deserializing")]
>     Json(#[from] serde_json::Error),
>     #[error("An error occured while parsing a color")]
>     HexColor(#[from] bevy::render::color::HexColorError),
> }
> ```
> 
> ## Solution
> 
> - Derive thiserror::Error the same way we do elsewhere (see query.rs for instance)
2022-05-30 18:13:35 +00:00
Matthias Schiffer
5256561b7a OrthographicProjection: place origin at integer pixel with WindowSize scaling mode (#4085)
# Objective

One way to avoid texture atlas bleeding is to ensure that every vertex is
placed at an integer pixel coordinate. This is a particularly appealing
solution for regular structures like tile maps.

Doing so is currently harder than necessary when the WindowSize scaling
mode and Center origin are used: For odd window width or height, the
origin of the coordinate system is placed in the middle of a pixel at
some .5 offset.

## Solution

Avoid this issue by rounding the half width and height values.
2022-05-30 15:14:12 +00:00
François
d353fbc6ea update image to 0.24 (#4121)
# Objective

- update image to 0.24

## Solution

- `Bgra*` variants support have been removed from image, remove them from Bevy code
- replace #4003 

changeling: https://github.com/image-rs/image/blob/master/CHANGES.md
2022-05-28 02:00:55 +00:00
Niklas Eicker
f271d734e6 Rename Color::as_hlsa_f32 to Color::as_hsla_f32 (#4827)
# Objective

Make the function consistent with returned values and `as_hsla` method

Fixes #4826 

## Solution

- Rename the method


## Migration Guide

- Rename the method
2022-05-25 17:46:58 +00:00
Teodor Tanasoaia
b6eededea4 Use uniform buffer usage for SkinnedMeshUniform instead of all usages (#4816)
# Objective

fixes #4811 (caused by #4339 [[exact change](https://github.com/bevyengine/bevy/pull/4339/files#diff-4bf3ed03d4129aad9f5678ba19f9b14ee8e3e61d6f6365e82197b01c74468b10R712-R721)] - where the buffer type has been changed from `UniformVec` to `BufferVec`)

## Solution

Use uniform buffer usage for `SkinnedMeshUniform` instead of all usages due to the `Default` derive.
2022-05-20 22:05:32 +00:00
Teodor Tanasoaia
7cb4d3cb43 Migrate to encase from crevice (#4339)
# Objective

- Unify buffer APIs
- Also see #4272

## Solution

- Replace vendored `crevice` with `encase`

---

## Changelog

Changed `StorageBuffer`
Added `DynamicStorageBuffer`
Replaced `UniformVec` with `UniformBuffer`
Replaced `DynamicUniformVec` with `DynamicUniformBuffer`

## Migration Guide

### `StorageBuffer`

removed `set_body()`, `values()`, `values_mut()`, `clear()`, `push()`, `append()`
added `set()`, `get()`, `get_mut()`

### `UniformVec` -> `UniformBuffer`

renamed `uniform_buffer()` to `buffer()`
removed `len()`, `is_empty()`, `capacity()`, `push()`, `reserve()`, `clear()`, `values()`
added `set()`, `get()`

### `DynamicUniformVec` -> `DynamicUniformBuffer`

renamed `uniform_buffer()` to `buffer()`
removed `capacity()`, `reserve()`


Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2022-05-18 21:09:21 +00:00
SarthakSingh31
dbd856de71 Nightly clippy fixes (#3491)
Fixes the following nightly clippy lints:
- ~~[map_flatten](https://rust-lang.github.io/rust-clippy/master/index.html#map_flatten)~~ (Fixed on main)
- ~~[needless_borrow](https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow)~~ (Fixed on main)
- [return_self_not_must_use](https://rust-lang.github.io/rust-clippy/master/index.html#return_self_not_must_use) (Added in 1.59.0)
- ~~[unnecessary_lazy_evaluations](https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_lazy_evaluations)~~ (Fixed on main)
- [extra_unused_lifetimes](https://rust-lang.github.io/rust-clippy/master/index.html#extra_unused_lifetimes) outside of macros
- [let_unit_value](https://rust-lang.github.io/rust-clippy/master/index.html#let_unit_value)
2022-05-17 04:38:03 +00:00
Daniel McNab
b1b3bd533b Skip drop when needs_drop is false (#4773)
# Objective

- We do a lot of function pointer calls in a hot loop (clearing entities in render). This is slow, since calling function pointers cannot be optimised out. We can avoid that in the cases where the function call is a no-op.
- Alternative to https://github.com/bevyengine/bevy/pull/2897
- On my machine, in `many_cubes`, this reduces dropping time from ~150μs to ~80μs.

## Solution
-  Make `drop` in `BlobVec` an `Option`, recording whether the given drop impl is required or not.
- Note that this does add branching in some cases - we could consider splitting this into two fields, i.e. unconditionally call the `drop` fn pointer.
- My intuition of how often types stored in `World` should have non-trivial drops makes me think that would be slower, however. 

N.B. Even once this lands, we should still test having a 'drop_multiple' variant - for types with a real `Drop` impl, the current implementation is definitely optimal.
2022-05-17 04:16:55 +00:00
Aron Derenyi
2e8dfc02ef Fixing confusing near and far fields in Camera (#4457)
# Objective

- Fixes #4456 

## Solution

- Removed the `near` and `far` fields from the camera and the views.

---

## Changelog

- Removed the `near` and `far` fields from the camera and the views.
- Removed the `ClusterFarZMode::CameraFarPlane` far z mode.

## Migration Guide

- Cameras no longer accept near and far values during initialization
- `ClusterFarZMode::Constant` should be used with the far value instead of `ClusterFarZMode::CameraFarPlane`
2022-05-16 16:37:33 +00:00
Jakob Hellermann
d3b2439c82 fix tracy frame marker placement (after preseting *all* windows) (#4731)
# Objective

The frame marker event was emitted in the loop of presenting all the windows. This would mark the frame as finished multiple times if more than one window is used.

## Solution

Move the frame marker to after the `for`-loop, so that it gets executed only once.
2022-05-12 18:39:20 +00:00
Joe Ardent
96078c76eb Make accessors for mesh vertices and indices public. (#3906)
# Objective

Make it easy to get position and index data from Meshes.

## Solution

It was previously possible to get the mesh data by manually matching on `Mesh::VertexAttributeValues` and `Mesh::Indices`as in the bodies of these two methods (`VertexAttributeValues::as_float3(&self)` and `Indices::iter(&self)`), but that's needless duplication that making these methods `pub` fixes.
2022-05-09 13:19:33 +00:00
Daniel McNab
b731ebad1b Allow closing windows at runtime (#3575)
# Objective

Fixes #3180, builds from https://github.com/bevyengine/bevy/pull/2898

## Solution

Support requesting a window to be closed and closing a window in `bevy_window`, and handle this in `bevy_winit`.

This is a stopgap until we move to windows as entites, which I'm sure I'll get around to eventually.

## Changelog

### Added

- `Window::close` to allow closing windows.
- `WindowClosed` to allow reacting to windows being closed.

### Changed

Replaced `bevy::system::exit_on_esc_system` with `bevy:🪟:close_on_esc`.

## Fixed

The app no longer exits when any window is closed. This difference is only observable when there are multiple windows. 

## Migration Guide

`bevy::input::system::exit_on_esc_system` has been removed. Use `bevy:🪟:close_on_esc` instead.
`CloseWindow` has been removed. Use `Window::close` instead.
The `Close` variant has been added to `WindowCommand`. Handle this by closing the relevant window.
2022-05-05 13:35:43 +00:00
Nionidh
558530871d StorageBuffer uses wrong type to calculate the buffer size. (#4557)
# Objective
Fixes #4556

## Solution
StorageBuffer must use the Size of the std430 representation to calculate the buffer size, as the std430 representation is the data that will be written to it.
2022-05-05 02:12:16 +00:00
Dusty DeWeese
82d849d3dc Add support for vertex colors (#4528)
# Objective

Add support for vertex colors

## Solution

This change is modeled after how vertex tangents are handled, so the shader is conditionally compiled with vertex color support if the mesh has the corresponding attribute set.

Vertex colors are multiplied by the base color. I'm not sure if this is the best for all cases, but may be useful for modifying vertex colors without creating a new mesh.

I chose `VertexFormat::Float32x4`, but I'd prefer 16-bit floats if/when support is added.

## Changelog

### Added
- Vertex colors can be specified using the `Mesh::ATTRIBUTE_COLOR` mesh attribute.
2022-05-05 00:46:32 +00:00
Rob Parrett
f8e0fc190a Add RegularPolygon and Circle meshes (#3730)
# Objective

Bevy users often want to create circles and other simple shapes.

All the machinery is in place to accomplish this, and there are external crates that help. But when writing code for e.g. a new bevy example, it's not really possible to draw a circle without bringing in a new asset, writing a bunch of scary looking mesh code, or adding a dependency.

In particular, this PR was inspired by this interaction in another PR: https://github.com/bevyengine/bevy/pull/3721#issuecomment-1016774535

## Solution

This PR adds `shape::RegularPolygon` and `shape::Circle` (which is just a `RegularPolygon` that defaults to a large number of sides)

## Discussion

There's a lot of ongoing discussion about shapes in <https://github.com/bevyengine/rfcs/pull/12> and at least one other lingering shape PR (although it seems incomplete).

That RFC currently includes `RegularPolygon` and `Circle` shapes, so I don't think that having working mesh generation code in the engine for those shapes would add much burden to an author of an implementation.

But if we'd prefer not to add additional shapes until after that's sorted out, I'm happy to close this for now.

## Alternatives for users

For any users stumbling on this issue, here are some plugins that will help if you need more shapes.

https://github.com/Nilirad/bevy_prototype_lyon
https://github.com/johanhelsing/bevy_smud
https://github.com/Weasy666/bevy_svg
https://github.com/redpandamonium/bevy_more_shapes
https://github.com/ForesightMiningSoftwareCorporation/bevy_polyline
2022-05-05 00:03:47 +00:00
François
4a9932fa8e simplified API to get NDC from camera and world position (#4041)
# Objective

- After #3412, `Camera::world_to_screen` got a little bit uglier to use by needing to provide both `Windows` and `Assets<Image>`, even though only one would be needed b697e73c3d/crates/bevy_render/src/camera/camera.rs (L117-L123)
- Some time, exact coordinates are not needed but normalized device coordinates is enough

## Solution

- Add a function to just get NDC
2022-05-03 19:51:18 +00:00
Jakob Hellermann
2b6e67f4cb add #[reflect(Default)] to create default value for reflected types (#3733)
### Problem
It currently isn't possible to construct the default value of a reflected type. Because of that, it isn't possible to use `add_component` of `ReflectComponent` to add a new component to an entity because you can't know what the initial value should be.

### Solution

1. add `ReflectDefault` type
```rust
#[derive(Clone)]
pub struct ReflectDefault {
    default: fn() -> Box<dyn Reflect>,
}

impl ReflectDefault {
    pub fn default(&self) -> Box<dyn Reflect> {
        (self.default)()
    }
}

impl<T: Reflect + Default> FromType<T> for ReflectDefault {
    fn from_type() -> Self {
        ReflectDefault {
            default: || Box::new(T::default()),
        }
    }
}
```

2. add `#[reflect(Default)]` to all component types that implement `Default` and are user facing (so not `ComputedSize`, `CubemapVisibleEntities` etc.)



This makes it possible to add the default value of a component to an entity without any compile-time information:

```rust
fn main() {
    let mut app = App::new();
    app.register_type::<Camera>();

    let type_registry = app.world.get_resource::<TypeRegistry>().unwrap();
    let type_registry = type_registry.read();

    let camera_registration = type_registry.get(std::any::TypeId::of::<Camera>()).unwrap();
    let reflect_default = camera_registration.data::<ReflectDefault>().unwrap();
    let reflect_component = camera_registration
        .data::<ReflectComponent>()
        .unwrap()
        .clone();

    let default = reflect_default.default();

    drop(type_registry);

    let entity = app.world.spawn().id();
    reflect_component.add_component(&mut app.world, entity, &*default);

    let camera = app.world.entity(entity).get::<Camera>().unwrap();
    dbg!(&camera);
}
```

### Open questions
- should we have `ReflectDefault` or `ReflectFromWorld` or both?
2022-05-03 19:20:13 +00:00
Robert Swain
479f43bbf3 Filter material handles on extraction (#4178)
# Objective

- While optimising many_cubes, I noticed that all material handles are extracted regardless of whether the entity to which the handle belongs is visible or not. As such >100k handles are extracted when only <20k are visible.

## Solution

- Only extract material handles of visible entities.
- This improves `many_cubes -- sphere` from ~42fps to ~48fps. It reduces not only the extraction time but also system commands time. `Handle<StandardMaterial>` extraction and its system commands went from 0.522ms + 3.710ms respectively, to 0.267ms + 0.227ms an 88% reduction for this system for this case. It's very view dependent but...
2022-05-03 18:28:04 +00:00
TheRawMeatball
73c78c3667 Use lifetimed, type erased pointers in bevy_ecs (#3001)
# Objective

`bevy_ecs` has large amounts of unsafe code which is hard to get right and makes it difficult to audit for soundness.

## Solution

Introduce lifetimed, type-erased pointers: `Ptr<'a>` `PtrMut<'a>` `OwningPtr<'a>'` and `ThinSlicePtr<'a, T>` which are newtypes around a raw pointer with a lifetime and conceptually representing strong invariants about the pointee and validity of the pointer.

The process of converting bevy_ecs to use these has already caught multiple cases of unsound behavior.

## Changelog

TL;DR for release notes: `bevy_ecs` now uses lifetimed, type-erased pointers internally, significantly improving safety and legibility without sacrificing performance. This should have approximately no end user impact, unless you were meddling with the (unfortunately public) internals of `bevy_ecs`.

- `Fetch`, `FilterFetch` and `ReadOnlyFetch` trait no longer have a `'state` lifetime
    - this was unneeded
- `ReadOnly/Fetch` associated types on `WorldQuery` are now on a new `WorldQueryGats<'world>` trait
    - was required to work around lack of Generic Associated Types (we wish to express `type Fetch<'a>: Fetch<'a>`)
- `derive(WorldQuery)` no longer requires `'w` lifetime on struct
    - this was unneeded, and improves the end user experience
- `EntityMut::get_unchecked_mut` returns `&'_ mut T` not `&'w mut T`
    - allows easier use of unsafe API with less footguns, and can be worked around via lifetime transmutery as a user
- `Bundle::from_components` now takes a `ctx` parameter to pass to the `FnMut` closure
    - required because closure return types can't borrow from captures
- `Fetch::init` takes `&'world World`, `Fetch::set_archetype` takes `&'world Archetype` and `&'world Tables`, `Fetch::set_table` takes `&'world Table`
    - allows types implementing `Fetch` to store borrows into world
- `WorldQuery` trait now has a `shrink` fn to shorten the lifetime in `Fetch::<'a>::Item`
    - this works around lack of subtyping of assoc types, rust doesnt allow you to turn `<T as Fetch<'static>>::Item'` into `<T as Fetch<'a>>::Item'`
    - `QueryCombinationsIter` requires this
- Most types implementing `Fetch` now have a lifetime `'w`
    - allows the fetches to store borrows of world data instead of using raw pointers

## Migration guide

- `EntityMut::get_unchecked_mut` returns a more restricted lifetime, there is no general way to migrate this as it depends on your code
- `Bundle::from_components` implementations must pass the `ctx` arg to `func`
- `Bundle::from_components` callers have to use a fn arg instead of closure captures for borrowing from world
- Remove lifetime args on `derive(WorldQuery)` structs as it is nonsensical
- `<Q as WorldQuery>::ReadOnly/Fetch` should be changed to either `RO/QueryFetch<'world>` or `<Q as WorldQueryGats<'world>>::ReadOnly/Fetch`
- `<F as Fetch<'w, 's>>` should be changed to `<F as Fetch<'w>>`
- Change the fn sigs of `Fetch::init/set_archetype/set_table` to match respective trait fn sigs
- Implement the required `fn shrink` on any `WorldQuery` implementations
- Move assoc types `Fetch` and `ReadOnlyFetch` on `WorldQuery` impls to `WorldQueryGats` impls
- Pass an appropriate `'world` lifetime to whatever fetch struct you are for some reason using

### Type inference regression

in some cases rustc may give spurrious errors when attempting to infer the `F` parameter on a query/querystate this can be fixed by manually specifying the type, i.e. `QueryState:🆕:<_, ()>(world)`. The error is rather confusing:

```rust=
error[E0271]: type mismatch resolving `<() as Fetch<'_>>::Item == bool`
    --> crates/bevy_pbr/src/render/light.rs:1413:30
     |
1413 |             main_view_query: QueryState::new(world),
     |                              ^^^^^^^^^^^^^^^ expected `bool`, found `()`
     |
     = note: required because of the requirements on the impl of `for<'x> FilterFetch<'x>` for `<() as WorldQueryGats<'x>>::Fetch`
note: required by a bound in `bevy_ecs::query::QueryState::<Q, F>::new`
    --> crates/bevy_ecs/src/query/state.rs:49:32
     |
49   |     for<'x> QueryFetch<'x, F>: FilterFetch<'x>,
     |                                ^^^^^^^^^^^^^^^ required by this bound in `bevy_ecs::query::QueryState::<Q, F>::new`
```

---

Made with help from @BoxyUwU and @alice-i-cecile 

Co-authored-by: Boxy <supbscripter@gmail.com>
2022-04-27 23:44:06 +00:00
bjorn3
ddce22b614 Decouple some dependencies (#3886)
# Objective

Reduce from scratch build time.

## Solution

Reduce the size of the critical path by removing dependencies between crates where not necessary. For `cargo check --no-default-features` this reduced build time from ~51s to ~45s. For some commits I am not completely sure if the tradeoff between build time reduction and convenience caused by the commit is acceptable. If not, I can drop them.
2022-04-27 19:08:11 +00:00
Rob Parrett
dafd7a14c9 Fix torus normals (#4520)
# Objective

Fix wonky torus normals.

## Solution

I attempted this previously in #3549, but it looks like I botched it. It seems like I mixed up the y/z axes. Somehow, the result looked okay from that particular camera angle.

This video shows toruses generated with
- [left, orange] original torus mesh code
- [middle, pink] PR 3549
- [right, purple] This PR

https://user-images.githubusercontent.com/200550/164093183-58a7647c-b436-4512-99cd-cf3b705cefb0.mov
2022-04-26 18:42:43 +00:00
SarthakSingh31
5155034a58 Converted exclusive systems to parallel systems wherever possible (#2774)
Closes #2767.

Converted:
- `play_queued_audio_system`
- `change_window`
2022-04-25 14:32:56 +00:00
KDecay
7a7f097485 Move Size to bevy_ui (#4285)
# Objective

- Related #4276.
- Part of the splitting process of #3503.

## Solution

- Move `Size` to `bevy_ui`.

## Reasons

- `Size` is only needed in `bevy_ui` (because it needs to use `Val` instead of `f32`), but it's also used as a worse `Vec2`  replacement in other areas.
- `Vec2` is more powerful than `Size` so it should be used whenever possible.
- Discussion in #3503.

## Changelog

### Changed

- The `Size` type got moved from `bevy_math` to `bevy_ui`.

## Migration Guide

- The `Size` type got moved from `bevy::math` to `bevy::ui`. To migrate you just have to import `bevy::ui::Size` instead of `bevy::math::Math` or use the `bevy::prelude` instead.

Co-authored-by: KDecay <KDecayMusic@protonmail.com>
2022-04-25 13:54:46 +00:00
nsarlin
0850975192 Add the possibility to create custom 2d orthographic cameras (#4048)
# Objective

- The `OrthographicCameraBundle` constructor for 2d cameras uses a hardcoded value for Z position and scale of the camera. It could be useful to be able to customize these values.

## Solution

- Add a new constructor `custom_2d` that takes `far` (Z position) and `scale` as parameters. The default constructor `new_2d` uses this constructor with `far = 1000.0` and `scale = 1.0`.
2022-04-25 13:54:44 +00:00
Yutao Yuan
8d67832dfa Bump Bevy to 0.8.0-dev (#4505)
# Objective

We should bump our version to 0.8.0-dev after releasing 0.7.0, according to our release checklist.

## Solution

Do it.
2022-04-17 23:04:52 +00:00
Carter Anderson
83c6ffb73c release 0.7.0 (#4487) 2022-04-15 18:05:37 +00:00
Dusty DeWeese
0d2b527faf Avoid windows with a physical size of zero (#4098)
# Objective

Fix #4097

## Solution

Return `None` from `RenderTarget::get_physical_size` if either dimension is zero.
2022-04-15 07:32:21 +00:00
Robert Swain
c2a9d5843d Faster assign lights to clusters (#4345)
# Objective

- Fixes #4234
- Fixes #4473 
- Built on top of #3989
- Improve performance of `assign_lights_to_clusters`

## Solution

- Remove the OBB-based cluster light assignment algorithm and calculation of view space AABBs
- Implement the 'iterative sphere refinement' algorithm used in Just Cause 3 by Emil Persson as documented in the Siggraph 2015 Practical Clustered Shading talk by Persson, on pages 42-44 http://newq.net/dl/pub/s2015_practical.pdf
- Adapt to also support orthographic projections
- Add `many_lights -- orthographic` for testing many lights using an orthographic projection

## Results

- `assign_lights_to_clusters` in `many_lights` before this PR on an M1 Max over 1500 frames had a median execution time of 1.71ms. With this PR it is 1.51ms, a reduction of 0.2ms or 11.7% for this system.

---

## Changelog

- Changed: Improved cluster light assignment performance

Co-authored-by: robtfm <50659922+robtfm@users.noreply.github.com>
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2022-04-15 02:53:20 +00:00
Dusty DeWeese
5a297d7903 Reuse texture when resolving multiple passes (#3552)
# Objective

Fixes https://github.com/bevyengine/bevy/issues/3499

## Solution

Uses a `HashMap` from `RenderTarget` to sampled textures when preparing `ViewTarget`s to ensure that two passes with the same render target get sampled to the same texture.

This builds on and depends on https://github.com/bevyengine/bevy/pull/3412, so this will be a draft PR until #3412 is merged. All changes for this PR are in the last commit.
2022-04-12 19:27:30 +00:00
Jakob Hellermann
193e8c4ada scene_viewer: load cameras (#4425)
# Objective

glTF files can contain cameras. Currently the scene viewer example uses _a_ camera defined in the file if possible, otherwise it spawns a new one. It would be nice if instead it could load all the cameras and cycle through them, while also having a separate user-controller camera.

## Solution

- instead of just a camera that is already defined, always spawn a new separate user-controller camera
- maintain a list of loaded cameras and cycle through them (wrapping to the user-controller camera) when pressing `C`

This matches the behavious that https://github.khronos.org/glTF-Sample-Viewer-Release/ has.

## Implementation notes

- The gltf scene asset loader just spawns the cameras into the world, but does not return a mapping of camera index to bevy entity. So instead the scene_viewer example just collects all spawned cameras with a good old `query.iter().collect()`, so the order is unspecified and may change between runs.

## Demo

https://user-images.githubusercontent.com/22177966/161826637-40161482-5b3b-4df5-aae8-1d5e9b918393.mp4


using the virtual city glTF sample file: https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/VC

Co-authored-by: Jakob Hellermann <hellermann@sipgate.de>
2022-04-11 22:56:06 +00:00
Jakob Hellermann
c12ee81822 bevy_app: add tracing event with tracy.frame_mark (#4320)
Currently `tracy` interprets the entire trace as one frame because the marker for frames isn't being recorded.

~~When an event with `tracy.trace_marker=true` is recorded, `tracing-tracy` will mark the frame as finished:
<aa0b96b2ae/tracing-tracy/src/lib.rs (L240)>~~

~~Unfortunately this leads to~~
```rs
INFO bevy_app:frame: bevy_app::app: finished frame tracy.frame_mark=true
```
~~being printed every frame (we can't use DEBUG because bevy_log sets `max_release_level_info`.~~

Instead of emitting an event that gets logged every frame, we can depend on tracy-client itself and call `finish_continuous_frame!();`
2022-04-08 22:50:23 +00:00
Kirillov Kirill
01bdf67c33 Improve the set_active_camera system (#4251)
# Objective

- Make `set_active_camera` system correctly respond to camera deletion, while preserving its correct behavior on first ever frame and any consequent frame, and with multiple cameras of the same type available in the world.
- Fixes #4227

## Solution

- Add a check that the entity referred to by `ActiveCamera` still exists in the world.
2022-04-07 23:30:47 +00:00
Robert Swain
c5963b4fd5 Use storage buffers for clustered forward point lights (#3989)
# Objective

- Make use of storage buffers, where they are available, for clustered forward bindings to support far more point lights in a scene
- Fixes #3605 
- Based on top of #4079 

This branch on an M1 Max can keep 60fps with about 2150 point lights of radius 1m in the Sponza scene where I've been testing. The bottleneck is mostly assigning lights to clusters which grows faster than linearly (I think 1000 lights was about 1.5ms and 5000 was 7.5ms). I have seen papers and presentations leveraging compute shaders that can get this up to over 1 million. That said, I think any further optimisations should probably be done in a separate PR.

## Solution

- Add `RenderDevice` to the `Material` and `SpecializedMaterial` trait `::key()` functions to allow setting flags on the keys depending on feature/limit availability
- Make `GpuPointLights` and `ViewClusterBuffers` into enums containing `UniformVec` and `StorageBuffer` variants. Implement the necessary API on them to make usage the same for both cases, and the only difference is at initialisation time.
- Appropriate shader defs in the shader code to handle the two cases

## Context on some decisions / open questions

- I'm using `max_storage_buffers_per_shader_stage >= 3` as a check to see if storage buffers are supported. I was thinking about diving into 'binding resource management' but it feels like we don't have enough use cases to understand the problem yet, and it is mostly a separate concern to this PR, so I think it should be handled separately.
- Should `ViewClusterBuffers` and `ViewClusterBindings` be merged, duplicating the count variables into the enum variants?


Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2022-04-07 16:16:35 +00:00
Hennadii Chernyshchyk
ea6e6f7db2 Do not crash if RenderDevice doesn't exist (#4427)
# Objective

Avoid crashing if `RenderDevice` doesn't exist (required for headless mode).
Fixes #4392.

## Solution

Use `CompressedImageFormats::all()` if there is no `RenderDevice`.
2022-04-05 19:37:23 +00:00
Francesco Giordana
dbd5e7ab6b Fixed case of R == G, following original conversion formula (#4383)
https://en.wikipedia.org/wiki/HSL_and_HSV#From_RGB

# Objective
Fixes #4382

## Solution

- Describe the solution used to achieve the objective above.
Fixed conversion formula to account for red and green component being max and equal
---

## Changelog
Fixed RGB -> HSL colorspace conversion

## Migration Guide


Co-authored-by: Francesco Giordana <fgiordana@netflix.com>
2022-04-04 18:59:00 +00:00
Light Ning
dd2001f2f1 bevy_render: add a small color box to each color (#4387)
# Objective

- bevy_render: add a small color box to each color

## Solution

![bevy_color_doc](https://user-images.githubusercontent.com/1318472/161241226-e7632a90-f526-44de-a68e-ff63b848164b.png)

---

## Changelog
2022-04-01 20:52:22 +00:00
devil ira
48ac955afd Fix loading non-TriangleList meshes without normals in gltf loader (#4376)
# Objective
Make it so that loading in a mesh without normals that is not a `TriangleList` succeeds.

## Solution
Flat normals can only be calculated on a mesh made of triangles.
Check whether the mesh is a `TriangleList` before trying to compute missing normals.

## Additional changes
The panic condition in `duplicate_vertices` did not make sense to me. I moved it to `compute_flat_normals` where the algorithm would produce incorrect results if the mesh is not a `TriangleList`.

Co-authored-by: devil-ira <justthecooldude@gmail.com>
2022-03-31 20:43:01 +00:00