Commit graph

284 commits

Author SHA1 Message Date
github-actions[bot]
920543c824 Release 0.9.0 (#6568)
Preparing next release
This PR has been auto-generated
2022-11-12 20:01:29 +00:00
Aevyrie
72fbcc7633 Fix color banding by dithering image before quantization (#5264)
# Objective

- Closes #5262 
- Fix color banding caused by quantization.

## Solution

- Adds dithering to the tonemapping node from #3425.
- This is inspired by Godot's default "debanding" shader: https://gist.github.com/belzecue/
- Unlike Godot:
  - debanding happens after tonemapping. My understanding is that this is preferred, because we are running the debanding at the last moment before quantization (`[f32, f32, f32, f32]` -> `f32`). This ensures we aren't biasing the dithering strength by applying it in a different (linear) color space.
  - This code instead uses and reference the origin source, Valve at GDC 2015

![Screenshot from 2022-11-10 13-44-46](https://user-images.githubusercontent.com/2632925/201218880-70f4cdab-a1ed-44de-a88c-8759e77197f1.png)
![Screenshot from 2022-11-10 13-41-11](https://user-images.githubusercontent.com/2632925/201218883-72393352-b162-41da-88bb-6e54a1e26853.png)


## Additional Notes 

Real time rendering to standard dynamic range outputs is limited to 8 bits of depth per color channel. Internally we keep everything in full 32-bit precision (`vec4<f32>`) inside passes and 16-bit between passes until the image is ready to be displayed, at which point the GPU implicitly converts our `vec4<f32>` into a single 32bit value per pixel, with each channel (rgba) getting 8 of those 32 bits.

### The Problem

8 bits of color depth is simply not enough precision to make each step invisible - we only have 256 values per channel! Human vision can perceive steps in luma to about 14 bits of precision. When drawing a very slight gradient, the transition between steps become visible because with a gradient, neighboring pixels will all jump to the next "step" of precision at the same time.

### The Solution

One solution is to simply output in HDR - more bits of color data means the transition between bands will become smaller. However, not everyone has hardware that supports 10+ bit color depth. Additionally, 10 bit color doesn't even fully solve the issue, banding will result in coherent bands on shallow gradients, but the steps will be harder to perceive.

The solution in this PR adds noise to the signal before it is "quantized" or resampled from 32 to 8 bits. Done naively, it's easy to add unneeded noise to the image. To ensure dithering is correct and absolutely minimal, noise is adding *within* one step of the output color depth. When converting from the 32bit to 8bit signal, the value is rounded to the nearest 8 bit value (0 - 255). Banding occurs around the transition from one value to the next, let's say from 50-51. Dithering will never add more than +/-0.5 bits of noise, so the pixels near this transition might round to 50 instead of 51 but will never round more than one step. This means that the output image won't have excess variance:
  - in a gradient from 49 to 51, there will be a step between each band at 49, 50, and 51.
  - Done correctly, the modified image of this gradient will never have a adjacent pixels more than one step (0-255) from each other.
  - I.e. when scanning across the gradient you should expect to see:
```
                  |-band-| |-band-| |-band-|
Baseline:         49 49 49 50 50 50 51 51 51
Dithered:         49 50 49 50 50 51 50 51 51
Dithered (wrong): 49 50 51 49 50 51 49 51 50
```

![Screenshot from 2022-11-10 14-12-36](https://user-images.githubusercontent.com/2632925/201219075-ab3f46be-d4e9-4869-b66b-a92e1706f49e.png)
![Screenshot from 2022-11-10 14-11-48](https://user-images.githubusercontent.com/2632925/201219079-ec5d2add-817d-487a-8fc1-84569c9cda73.png)




You can see from above how correct dithering "fuzzes" the transition between bands to reduce distinct steps in color, without adding excess noise.

### HDR

The previous section (and this PR) assumes the final output is to an 8-bit texture, however this is not always the case. When Bevy adds HDR support, the dithering code will need to take the per-channel depth into account instead of assuming it to be 0-255. Edit: I talked with Rob about this and it seems like the current solution is okay. We may need to revisit once we have actual HDR final image output.

---

## Changelog

### Added

- All pipelines now support deband dithering. This is enabled by default in 3D, and can be toggled in the `Tonemapping` component in camera bundles. Banding is a graphical artifact created when the rendered image is crunched from high precision (f32 per color channel) down to the final output (u8 per channel in SDR). This results in subtle gradients becoming blocky due to the reduced color precision. Deband dithering applies a small amount of noise to the signal before it is "crunched", which breaks up the hard edges of blocks (bands) of color. Note that this does not add excess noise to the image, as the amount of noise is less than a single step of a color channel - just enough to break up the transition between color blocks in a gradient.


Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2022-11-11 19:43:45 +00:00
Robert Swain
c4e791d628 bevy_pbr: Normalize skinned normals (#6543)
# Objective

- Make the many foxes not unnecessarily bright. Broken since #5666.
- Fixes #6528 

## Solution

- In #5666 normalisation of normals was moved from the fragment stage to the vertex stage. However, it was not added to the vertex stage for skinned normals. The many foxes are skinned and their skinned normals were not unit normals. which made them brighter. Normalising the skinned normals fixes this.

---

## Changelog

- Fixed: Non-unit length skinned normals are now normalized.
2022-11-11 03:31:57 +00:00
Jakob Hellermann
4ad621fe0f Reflect for Tonemapping and ClusterConfig (#6488)
# Objective

- it would be useful to inspect these structs using reflection

## Solution

- derive and register reflect
- Note that `#[reflect(Component)]` requires `Default` (or `FromWorld`) until #6060, so I implemented `Default` for `Tonemapping` with `is_enabled: false`
2022-11-07 19:44:17 +00:00
Rob Parrett
1170b30785 Fix panic when using globals uniform in wasm builds (#6460)
# Objective

Fixes #5393 

## Solution

- Add padding to `GlobalsUniform` / `Globals` to make it 16-byte aligned.

Still not super clear on whether this is a `naga` thing or an `encase` thing or what. But now that we're offering `globals` up to users and #5393 is not just breaking an example, maybe we should do this sort of workaround?
2022-11-07 19:44:14 +00:00
TimJentzsch
694c980c82 Fix clippy::iter_with_drain (#6485)
# Objective

Fixes #6483.

- Fix the [`clippy::iter_with_drain`](https://rust-lang.github.io/rust-clippy/master/index.html#iter_with_drain) warnings
- From the docs: "`.into_iter()` is simpler with better performance"

## Solution

- Replace `.drain(..)` for `Vec` with `.into_iter()`
2022-11-06 01:42:15 +00:00
Carter Anderson
e5905379de Use new let-else syntax where possible (#6463)
# Objective

Let-else syntax is now stable!

## Solution

Use it where possible!
2022-11-04 21:32:09 +00:00
Marco Buono
1bd3d85769 Take DirectionalLight's GlobalTransform into account when calculating shadow map volume (not just direction) (#6384)
# Objective

This PR fixes #5789, by enabling movable (and scalable) directional light shadow volumes.

## Solution

This PR changes `ExtractedDirectionalLight` to hold a copy of the `DirectionalLight` entity's `GlobalTransform`, instead of just a `direction` vector. This allows the shadow map volume (as defined by the light's `shadow_projection` field) to be transformed honoring translation _and_ scale transforms, and not just rotation.

It also augments the texel size calculation (used to determine the `shadow_normal_bias`) so that it now takes into account the upper bound of the x/y/z scale of the `GlobalTransform`.

This change makes the directional light extraction code more consistent with point and spot lights (that already use `transform`), and allows easily moving and scaling the shadow volume along with a player entity based on camera distance/angle, immediately enabling more real world use cases until we have a more sophisticated adaptive implementation, such as the one described in #3629.

**Note:** While it was previously possible to update the projection achieving a similar effect, depending on the light direction and distance to the origin, the fact that the shadow map camera was always positioned at the origin with a hardcoded `Vec3::Y` up value meant you would get sub-optimal or inconsistent/incorrect results.

---

## Changelog

### Changed

- `DirectionalLight` shadow volumes now honor translation and scale transforms

## Migration Guide

- If your directional lights were positioned at the origin and not scaled (the default, most common scenario) no changes are needed on your part; it just works as before;
- If you previously had a system for dynamically updating directional light shadow projections, you might now be able to simplify your code by updating the directional light entity's transform instead;
- In the unlikely scenario that a scene with directional lights that previously rendered shadows correctly has missing shadows, make sure your directional lights are positioned at (0, 0, 0) and are not scaled to a size that's too large or too small.
2022-11-04 20:12:26 +00:00
JMS55
4c4f47697c Bloom (#6397)
# Objective

- Adds a bloom pass for HDR-enabled Camera3ds.
- Supersedes (and all credit due to!) https://github.com/bevyengine/bevy/pull/3430 and https://github.com/bevyengine/bevy/pull/2876

![image](https://user-images.githubusercontent.com/47158642/198698783-228edc00-20b5-4218-a613-331ccd474f38.png)

## Solution

- A threshold is applied to isolate emissive samples, and then a series of downscale and upscaling passes are applied and composited together.
- Bloom is applied to 2d or 3d Cameras with hdr: true and a BloomSettings component.

---

## Changelog

- Added a `core_pipeline::bloom::BloomSettings` component.
- Added `BloomNode` that runs between the main pass and tonemapping.
- Added a `BloomPlugin` that is loaded as part of CorePipelinePlugin.
- Added a bloom example project.

Co-authored-by: JMS55 <47158642+JMS55@users.noreply.github.com>
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
Co-authored-by: DGriffin91 <github@dgdigital.net>
2022-11-04 01:34:12 +00:00
Robert Swain
fc56c686af bevy_pbr: Fix incorrect and unnecessary normal-mapping code (#5766)
# Objective

- Fixes #4019 
- Fix lighting of double-sided materials when using a negative scale
- The FlightHelmet.gltf model's hose uses a double-sided material. Loading the model with a uniform scale of -1.0, and comparing against Blender, it was identified that negating the world-space tangent, bitangent, and interpolated normal produces incorrect lighting. Discussion with Morten Mikkelsen clarified that this is both incorrect and unnecessary.

## Solution

- Remove the code that negates the T, B, and N vectors (the interpolated world-space tangent, calculated world-space bitangent, and interpolated world-space normal) when seeing the back face of a double-sided material with negative scale.
- Negate the world normal for a double-sided back face only when not using normal mapping

### Before, on `main`, flipping T, B, and N

<img width="932" alt="Screenshot 2022-08-22 at 15 11 53" src="https://user-images.githubusercontent.com/302146/185965366-f776ff2c-cfa1-46d1-9c84-fdcb399c273c.png">

### After, on this PR

<img width="932" alt="Screenshot 2022-08-22 at 15 12 11" src="https://user-images.githubusercontent.com/302146/185965420-8be493e2-3b1a-4188-bd13-fd6b17a76fe7.png">

### Double-sided material without normal maps

https://user-images.githubusercontent.com/302146/185988113-44a384e7-0b55-4946-9b99-20f8c803ab7e.mp4

---

## Changelog

- Fixed: Lighting of normal-mapped, double-sided materials applied to models with negative scale
- Fixed: Lighting and shadowing of back faces with no normal-mapping and a double-sided material

## Migration Guide

`prepare_normal` from the `bevy_pbr::pbr_functions` shader import has been reworked.

Before:
```rust
    pbr_input.world_normal = in.world_normal;

    pbr_input.N = prepare_normal(
        pbr_input.material.flags,
        in.world_normal,
#ifdef VERTEX_TANGENTS
#ifdef STANDARDMATERIAL_NORMAL_MAP
        in.world_tangent,
#endif
#endif
        in.uv,
        in.is_front,
    );
```

After:
```rust
    pbr_input.world_normal = prepare_world_normal(
        in.world_normal,
        (material.flags & STANDARD_MATERIAL_FLAGS_DOUBLE_SIDED_BIT) != 0u,
        in.is_front,
    );

    pbr_input.N = apply_normal_mapping(
        pbr_input.material.flags,
        pbr_input.world_normal,
#ifdef VERTEX_TANGENTS
#ifdef STANDARDMATERIAL_NORMAL_MAP
        in.world_tangent,
#endif
#endif
        in.uv,
    );
```
2022-11-03 20:37:32 +00:00
ira
262b3fc40d Fix mesh.wgsl error for meshes without normals (#6439)
# Objective
Split `model` assignment out of `#ifdef VERTEX_NORMALS`.
Remove outdated code/comments talking about required mesh attributes. 

Co-authored-by: devil-ira <justthecooldude@gmail.com>
2022-11-03 12:38:47 +00:00
Kurt Kühnert
701ed8c59f Increase the MAX_DIRECTIONAL_LIGHTS from 1 to 10 (#6066)
# Objective

Currently we are limiting the amount of direction lights in a scene to one.

## Solution

Increase the amount of direction lights from 1 to 10. 
This still is not a perfect solution, but should unblock many use cases.
We could probably just store the directional lights similar to the point lights in an storage buffer, allowing for an variable amount of directional lights.


Co-authored-by: Kurt Kühnert <51823519+Ku95@users.noreply.github.com>
2022-11-03 07:09:51 +00:00
Alice Cecile
334e09892b Revert "Show prelude re-exports in docs (#6448)" (#6449)
This reverts commit 53d387f340.

# Objective

Reverts #6448. This didn't have the intended effect: we're now getting bevy::prelude shown in the docs again.

Co-authored-by: Alejandro Pascual <alejandro.pascual.pozo@gmail.com>
2022-11-02 20:40:45 +00:00
Alejandro Pascual
53d387f340 Show prelude re-exports in docs (#6448)
# Objective

- Right now re-exports are completely hidden in prelude docs.
- Fixes #6433

## Solution

- We could show the re-exports without inlining their documentation.
2022-11-02 19:35:06 +00:00
Griffin
5640ec855e Add FXAA postprocessing (#6393)
# Objective

- Add post processing passes for FXAA (Fast Approximate Anti-Aliasing)
- Add example comparing MSAA and FXAA

## Solution

When the FXAA plugin is added, passes for FXAA are inserted between the main pass and the tonemapping pass. Supports using either HDR or LDR output from the main pass.

---

## Changelog

- Add a new FXAANode that runs after the main pass when the FXAA plugin is added.

Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2022-11-02 06:51:28 +00:00
Yoh Deadfall
8b9aa2cceb Freeing memory held by visible entities vector (#3009)
- Freeing unused memory held by visible entities
- Fixed comment style

# Objective

With Rust 1.56 it's possible to shrink vectors to a specified capacity. Visibility system had a comment before asking for that feature to free unused memory by a vector if its capacity is two times larger than the length.

## Solution

Shrinking the vector of visible entities to the nearest power of 2 elements next to `len()`, if capacity exceeds it more than two times.
2022-10-31 15:36:08 +00:00
JoJoJet
336049da68 Remove outdated uses of single-tuple bundles (#6406)
# Objective

Bevy still has many instances of using single-tuples `(T,)` to create a bundle. Due to #2975, this is no longer necessary.

## Solution

Search for regex `\(.+\s*,\)`. This should have found every instance.
2022-10-29 18:15:28 +00:00
Jakob Hellermann
e71c4d2802 fix nightly clippy warnings (#6395)
# Objective

- fix new clippy lints before they get stable and break CI

## Solution

- run `clippy --fix` to auto-fix machine-applicable lints
- silence `clippy::should_implement_trait` for `fn HandleId::default<T: Asset>`

## Changes
- always prefer `format!("{inline}")` over `format!("{}", not_inline)`
- prefer `Box::default` (or `Box::<T>::default` if necessary) over `Box::new(T::default())`
2022-10-28 21:03:01 +00:00
Jakob Hellermann
f867319336 add ReflectAsset and ReflectHandle (#5923)
# Objective
![image](https://user-images.githubusercontent.com/22177966/189350194-639a0211-e984-4f73-ae62-0ede44891eb9.png)

^ enable this

Concretely, I need to
- list all handle ids for an asset type
- fetch the asset as `dyn Reflect`, given a `HandleUntyped`
- when encountering a `Handle<T>`, find out what asset type that handle refers to (`T`'s type id) and turn the handle into a `HandleUntyped`

## Solution

- add `ReflectAsset` type containing function pointers for working with assets
```rust
pub struct ReflectAsset {
    type_uuid: Uuid,
    assets_resource_type_id: TypeId, // TypeId of the `Assets<T>` resource

    get: fn(&World, HandleUntyped) -> Option<&dyn Reflect>,
    get_mut: fn(&mut World, HandleUntyped) -> Option<&mut dyn Reflect>,
    get_unchecked_mut: unsafe fn(&World, HandleUntyped) -> Option<&mut dyn Reflect>,
    add: fn(&mut World, &dyn Reflect) -> HandleUntyped,
    set: fn(&mut World, HandleUntyped, &dyn Reflect) -> HandleUntyped,
    len: fn(&World) -> usize,
    ids: for<'w> fn(&'w World) -> Box<dyn Iterator<Item = HandleId> + 'w>,
    remove: fn(&mut World, HandleUntyped) -> Option<Box<dyn Reflect>>,
}
```
- add `ReflectHandle` type relating the handle back to the asset type and providing a way to create a `HandleUntyped`
```rust
pub struct ReflectHandle {
    type_uuid: Uuid,
    asset_type_id: TypeId,
    downcast_handle_untyped: fn(&dyn Any) -> Option<HandleUntyped>,
}
```
- add the corresponding `FromType` impls
- add a function `app.register_asset_reflect` which is supposed to be called after `.add_asset` and registers `ReflectAsset` and `ReflectHandle` in the type registry
---

## Changelog

- add `ReflectAsset` and `ReflectHandle` types, which allow code to use reflection to manipulate arbitrary assets without knowing their types at compile time
2022-10-28 20:42:33 +00:00
JoJoJet
456971381c Resolve most remaining execution-order ambiguities (#6341)
# Objective

Bevy's internal plugins have lots of execution-order ambiguities, which makes the ambiguity detection tool very noisy for our users.

## Solution

Silence every last ambiguity that can currently be resolved.
Each time an ambiguity is silenced, it is accompanied by a comment describing why it is correct. This description should be based on the public API of the respective systems. Thus, I have added documentation to some systems describing how they use some resources.

# Future work

Some ambiguities remain, due to issues out of scope for this PR. 

* The ambiguity checker does not respect `Without<>` filters, leading to false positives.
* Ambiguities between `bevy_ui` and `bevy_animation` cannot be resolved, since neither crate knows that the other exists. We will need a general solution to this problem.
2022-10-27 12:56:03 +00:00
Jakob Hellermann
838b318863 separate tonemapping and upscaling passes (#3425)
Attempt to make features like bloom https://github.com/bevyengine/bevy/pull/2876 easier to implement.

**This PR:**
- Moves the tonemapping from `pbr.wgsl` into a separate pass
- also add a separate upscaling pass after the tonemapping which writes to the swap chain (enables resolution-independant rendering and post-processing after tonemapping)
- adds a `hdr` bool to the camera which controls whether the pbr and sprite shaders render into a `Rgba16Float` texture

**Open questions:**
- ~should the 2d graph work the same as the 3d one?~ it is the same now
- ~The current solution is a bit inflexible because while you can add a post processing pass that writes to e.g. the `hdr_texture`, you can't write to a separate `user_postprocess_texture` while reading the `hdr_texture` and tell the tone mapping pass to read from the `user_postprocess_texture` instead. If the tonemapping and upscaling render graph nodes were to take in a `TextureView` instead of the view entity this would almost work, but the bind groups for their respective input textures are already created in the `Queue` render stage in the hardcoded order.~ solved by creating bind groups in render node

**New render graph:**

![render_graph](https://user-images.githubusercontent.com/22177966/147767249-57dd4229-cfab-4ec5-9bf3-dc76dccf8e8b.png)
<details>
<summary>Before</summary>

![render_graph_old](https://user-images.githubusercontent.com/22177966/147284579-c895fdbd-4028-41cf-914c-e1ffef60e44e.png)
</details>

Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2022-10-26 20:13:59 +00:00
ira
b291223e34 Implement IntoIterator for ECS wrapper types. (#5096)
# Objective

Improve ergonomics by passing on the `IntoIterator` impl of the underlying type to wrapper types.

## Solution

Implement `IntoIterator` for ECS wrapper types (Mut, Local, Res, etc.).

Co-authored-by: devil-ira <justthecooldude@gmail.com>
2022-10-24 21:01:08 +00:00
Torstein Grindvik
cb5e2d84be Use wgsl saturate (#6318)
# Objective

Use saturate wgsl function now implemented in naga (version 0.10.0). There is now no need for one in utils.wgsl.

naga's version allows usage for not only scalars but vectors as well.

## Solution

Remove the utils.wgsl saturate function.

## Changelog

Remove saturate function from utils.wgsl in favor of saturate in naga v0.10.0.
2022-10-22 08:37:51 +00:00
Charles
740ae9a37f remove mandatory mesh attributes (#6127)
# Objective

- It's possible to create a mesh without positions or normals, but currently bevy forces these attributes to be present on any mesh.

## Solution

- Don't assume these attributes are present and add a shader defs for each attributes
- I updated 2d and 3d meshes to use the same logic.

---

## Changelog

- Meshes don't require any attributes

# Notes
I didn't update the pbr.wgsl shader because I'm not sure how to handle it. It doesn't really make sense to use it without positions or normals.
2022-10-10 17:58:15 +00:00
VitalyR
f5322cd757 get proper texture format after the renderer is initialized, fix #3897 (#5413)
# Objective
There is no Srgb support on some GPU and display protocols with `winit` (for example, Nvidia's GPUs with Wayland). Thus `TextureFormat::bevy_default()` which returns `Rgba8UnormSrgb` or `Bgra8UnormSrgb` will cause panics on such platforms. This patch will resolve this problem. Fix https://github.com/bevyengine/bevy/issues/3897.

## Solution

Make `initialize_renderer` expose `wgpu::Adapter` and `first_available_texture_format`, use the `first_available_texture_format` by default.

## Changelog

* Fixed https://github.com/bevyengine/bevy/issues/3897.
2022-10-10 16:10:05 +00:00
robtfm
29098b7a11 fix spot dir nan bug (#6167)
# Objective

fix error with pbr shader's spotlight direction calculation when direction.y ~= 0

## Solution

in pbr_lighting.wgsl, clamp `1-x^2-z^2` to `>= 0` so that we can safely `sqrt` it
2022-10-05 12:00:07 +00:00
Sludge
ac364e9e28 Register Wireframe type (#6152)
# Objective

The `Wireframe` type implements `Reflect`, but is never registered, making its reflection inaccessible.

## Solution

Call `App::register_type::<Wireframe>()` in the `Plugin::build` implementation of `WireframePlugin`.

---

## Changelog

Fixed `Wireframe` type reflection not getting registered.
2022-10-03 16:37:03 +00:00
Nicola Papale
6b8cc2652a Document all StandardMaterial fields (#5921)
# Objective

Add more documentation on `StandardMaterial` and improve
consistency on existing doc.

Co-authored-by: Nicola Papale <nicopap@users.noreply.github.com>
2022-09-28 21:20:29 +00:00
Charles
197392a2cd use alpha mask even when unlit (#6047)
# Objective

- Alpha mask was previously ignored when using an unlit material. 
- Fixes https://github.com/bevyengine/bevy/issues/4479

## Solution

- Extract the alpha discard to a separate function and use it when unlit is true

## Notes
I tried calling `alpha_discard()` before the `if` in pbr.wgsl, but I had errors related to having a `discard` at the beginning before doing the texture sampling. I'm not sure if there's a way to fix that instead of having the function being called in 2 places.
2022-09-28 05:54:11 +00:00
Charles
8073362039 add globals to mesh view bind group (#5409)
# Objective

- It's often really useful to have access to the time when writing shaders.

## Solution

- Add a UnifformBuffer in the mesh view bind group
- This buffer contains the time, delta time and a wrapping frame count

https://user-images.githubusercontent.com/8348954/180130314-97948c2a-2d11-423d-a9c4-fb5c9d1892c7.mp4

---

## Changelog

- Added a `GlobalsUniform` at position 9 of the mesh view bind group

## Notes

The implementation is currently split between bevy_render and bevy_pbr because I was basing my implementation on the `ViewPlugin`. I'm not sure if that's the right way to structure it.

I named this `globals` instead of just time because we could potentially add more things to it.

## References in other engines

- Godot: <https://docs.godotengine.org/en/stable/tutorials/shaders/shader_reference/canvas_item_shader.html#global-built-ins>
    - Global time since startup, in seconds, by default resets to 0 after 3600 seconds
    - Doesn't seem to have anything else
- Unreal: <https://docs.unrealengine.com/4.26/en-US/RenderingAndGraphics/Materials/ExpressionReference/Constant/>
    - Generic time value that updates every frame. Can be paused or scaled.
    - Frame count node, doesn't seem to be an equivalent for shaders: <https://docs.unrealengine.com/4.26/en-US/BlueprintAPI/Utilities/GetFrameCount/>
- Unity: <https://docs.unity3d.com/Manual/SL-UnityShaderVariables.html>
    - time since startup in seconds. No mention of time wrapping. Stored as a `vec4(t/20, t, t*2, t*3)` where `t` is the value in seconds
    - Also has delta time, sin time and cos time
- ShaderToy: <https://www.shadertoy.com/howto>
    - iTime is the time since startup in seconds.
    - iFrameRate
    - iTimeDelta
    - iFrame frame counter

Co-authored-by: Charles <IceSentry@users.noreply.github.com>
2022-09-28 04:20:27 +00:00
Martin Lysell
180c94cc13 Fix some outdated file reference comments in bevy_pbr (#6111)
# Objective

Simple docs/comments only PR that just fixes some outdated file references left over from the render rewrite.

## Solution

- Change the references to point to the correct files
2022-09-27 17:51:12 +00:00
Carter Anderson
dc3f801239 Exclusive Systems Now Implement System. Flexible Exclusive System Params (#6083)
# Objective

The [Stageless RFC](https://github.com/bevyengine/rfcs/pull/45) involves allowing exclusive systems to be referenced and ordered relative to parallel systems. We've agreed that unifying systems under `System` is the right move.

This is an alternative to #4166 (see rationale in the comments I left there). Note that this builds on the learnings established there (and borrows some patterns).

## Solution

This unifies parallel and exclusive systems under the shared `System` trait, removing the old `ExclusiveSystem` trait / impls. This is accomplished by adding a new `ExclusiveFunctionSystem` impl similar to `FunctionSystem`. It is backed by `ExclusiveSystemParam`, which is similar to `SystemParam`. There is a new flattened out SystemContainer api (which cuts out a lot of trait and type complexity). 

This means you can remove all cases of `exclusive_system()`:

```rust
// before
commands.add_system(some_system.exclusive_system());
// after
commands.add_system(some_system);
```

I've also implemented `ExclusiveSystemParam` for `&mut QueryState` and `&mut SystemState`, which makes this possible in exclusive systems:

```rust
fn some_exclusive_system(
    world: &mut World,
    transforms: &mut QueryState<&Transform>,
    state: &mut SystemState<(Res<Time>, Query<&Player>)>,
) {
    for transform in transforms.iter(world) {
        println!("{transform:?}");
    }
    let (time, players) = state.get(world);
    for player in players.iter() {
        println!("{player:?}");
    }
}
```

Note that "exclusive function systems" assume `&mut World` is present (and the first param). I think this is a fair assumption, given that the presence of `&mut World` is what defines the need for an exclusive system.

I added some targeted SystemParam `static` constraints, which removed the need for this:
``` rust
fn some_exclusive_system(state: &mut SystemState<(Res<'static, Time>, Query<&'static Player>)>) {}
```

## Related

- #2923
- #3001
- #3946

## Changelog

- `ExclusiveSystem` trait (and implementations) has been removed in favor of sharing the `System` trait.
- `ExclusiveFunctionSystem` and `ExclusiveSystemParam` were added, enabling flexible exclusive function systems
- `&mut SystemState` and `&mut QueryState` now implement `ExclusiveSystemParam`
- Exclusive and parallel System configuration is now done via a unified `SystemDescriptor`, `IntoSystemDescriptor`, and `SystemContainer` api.

## Migration Guide

Calling `.exclusive_system()` is no longer required (or supported) for converting exclusive system functions to exclusive systems:

```rust
// Old (0.8)
app.add_system(some_exclusive_system.exclusive_system());
// New (0.9)
app.add_system(some_exclusive_system);
```

Converting "normal" parallel systems to exclusive systems is done by calling the exclusive ordering apis:

```rust
// Old (0.8)
app.add_system(some_system.exclusive_system().at_end());
// New (0.9)
app.add_system(some_system.at_end());
```

Query state in exclusive systems can now be cached via ExclusiveSystemParams, which should be preferred for clarity and performance reasons:
```rust
// Old (0.8)
fn some_system(world: &mut World) {
  let mut transforms = world.query::<&Transform>();
  for transform in transforms.iter(world) {
  }
}
// New (0.9)
fn some_system(world: &mut World, transforms: &mut QueryState<&Transform>) {
  for transform in transforms.iter(world) {
  }
}
```
2022-09-26 23:57:07 +00:00
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();
```
2022-09-23 19:55:54 +00:00
Carter Anderson
cd15f0f5be Accept Bundles for insert and remove. Deprecate insert/remove_bundle (#6039)
# Objective

Take advantage of the "impl Bundle for Component" changes in #2975 / add the follow up changes discussed there.

## Solution

- Change `insert` and `remove` to accept a Bundle instead of a Component (for both Commands and World)
- Deprecate `insert_bundle`, `remove_bundle`, and `remove_bundle_intersection`
- Add `remove_intersection`

---

## Changelog

- Change `insert` and `remove` now accept a Bundle instead of a Component (for both Commands and World)
- `insert_bundle` and `remove_bundle` are deprecated
 

## Migration Guide

Replace `insert_bundle` with `insert`:
```rust
// Old (0.8)
commands.spawn().insert_bundle(SomeBundle::default());
// New (0.9)
commands.spawn().insert(SomeBundle::default());
```

Replace `remove_bundle` with `remove`:
```rust
// Old (0.8)
commands.entity(some_entity).remove_bundle::<SomeBundle>();
// New (0.9)
commands.entity(some_entity).remove::<SomeBundle>();
```

Replace `remove_bundle_intersection` with `remove_intersection`:
```rust
// Old (0.8)
world.entity_mut(some_entity).remove_bundle_intersection::<SomeBundle>();
// New (0.9)
world.entity_mut(some_entity).remove_intersection::<SomeBundle>();
```

Consider consolidating as many operations as possible to improve ergonomics and cut down on archetype moves:
```rust
// Old (0.8)
commands.spawn()
  .insert_bundle(SomeBundle::default())
  .insert(SomeComponent);

// New (0.9) - Option 1
commands.spawn().insert((
  SomeBundle::default(),
  SomeComponent,
))

// New (0.9) - Option 2
commands.spawn_bundle((
  SomeBundle::default(),
  SomeComponent,
))
```

## Next Steps

Consider changing `spawn` to accept a bundle and deprecate `spawn_bundle`.
2022-09-21 21:47:53 +00:00
ira
2b80a3f279 Implement IntoIterator for &Extract<P> (#6025)
# Objective

Implement `IntoIterator` for `&Extract<P>` if the system parameter it wraps implements `IntoIterator`.

Enables the use of `IntoIterator` with an extracted query.

Co-authored-by: devil-ira <justthecooldude@gmail.com>
2022-09-20 00:29:10 +00:00
robtfm
503c2a9677 adjust cluster index for viewport origin (#5947)
# Objective

fixes #5946

## Solution

adjust cluster index calculation for viewport origin.

from reading point 2 of the rasterization algorithm description in https://gpuweb.github.io/gpuweb/#rasterization, it looks like framebuffer space (and so @bulitin(position)) is not meant to be adjusted for viewport origin, so we need to subtract that to get the right cluster index.

- add viewport origin to rust `ExtractedView` and wgsl `View` structs
- subtract from frag coord for cluster index calculation
2022-09-15 21:58:14 +00:00
ira
b42f426fc3 Add associated constant IDENTITY to Transform and friends. (#5340)
# Objective
Since `identity` is a const fn that takes no arguments it seems logical to make it an associated constant.
This is also more in line with types from glam (eg. `Quat::IDENTITY`).

## Migration Guide

The method `identity()` on `Transform`, `GlobalTransform` and `TransformBundle` has been deprecated.
Use the associated constant `IDENTITY` instead.

Co-authored-by: devil-ira <justthecooldude@gmail.com>
2022-08-30 22:10:24 +00:00
Lain-dono
24e5e10cd4 Use 3 bits of PipelineKey to store MSAA sample count (#5826)
Sample count always power of two. Thus, it is enough to store `log2(sample_count)`.
This can be implemented using [u32::trailing_zeros](https://doc.rust-lang.org/stable/std/primitive.u32.html#method.trailing_zeros). Then we can restore sample count with the `1 << stored`.
You get 3 bits instead of 6 and up to 128x MSAA. This is more than is supported by any common hardware.

Full table of possible variations:

```
    original MSAA sample count      stored    loaded
* 00000000000000000000000000000000 -> 000 -> 00000001  1
  00000000000000000000000000000001 -> 000 -> 00000001  1
  00000000000000000000000000000010 -> 001 -> 00000010  2
  00000000000000000000000000000100 -> 010 -> 00000100  4
  00000000000000000000000000001000 -> 011 -> 00001000  8
  00000000000000000000000000010000 -> 100 -> 00010000  16
  00000000000000000000000000100000 -> 101 -> 00100000  32
  00000000000000000000000001000000 -> 110 -> 01000000  64
  00000000000000000000000010000000 -> 111 -> 10000000  128
* 00000000000000000000000100000000 -> 000 -> 00000001  256
* 00000000000000000000001000000000 -> 001 -> 00000010  512
* 00000000000000000000010000000000 -> 010 -> 00000100  1024
* 00000000000000000000100000000000 -> 011 -> 00001000  2048
* 00000000000000000001000000000000 -> 100 -> 00010000  4096
* 00000000000000000010000000000000 -> 101 -> 00100000  8192
* 00000000000000000100000000000000 -> 110 -> 01000000  16384
* 00000000000000001000000000000000 -> 111 -> 10000000  32768
* 00000000000000010000000000000000 -> 000 -> 00000001  65536
* 00000000000000100000000000000000 -> 001 -> 00000010  131072
* 00000000000001000000000000000000 -> 010 -> 00000100  262144
* 00000000000010000000000000000000 -> 011 -> 00001000  524288
* 00000000000100000000000000000000 -> 100 -> 00010000  1048576
* 00000000001000000000000000000000 -> 101 -> 00100000  2097152
* 00000000010000000000000000000000 -> 110 -> 01000000  4194304
* 00000000100000000000000000000000 -> 111 -> 10000000  8388608
* 00000001000000000000000000000000 -> 000 -> 00000001  16777216
* 00000010000000000000000000000000 -> 001 -> 00000010  33554432
* 00000100000000000000000000000000 -> 010 -> 00000100  67108864
* 00001000000000000000000000000000 -> 011 -> 00001000  134217728
* 00010000000000000000000000000000 -> 100 -> 00010000  268435456
* 00100000000000000000000000000000 -> 101 -> 00100000  536870912
* 01000000000000000000000000000000 -> 110 -> 01000000  1073741824
* 10000000000000000000000000000000 -> 111 -> 10000000  2147483648
```
2022-08-30 03:00:39 +00:00
Robert Swain
681c9c6dc8 bevy_pbr: Fix tangent and normal normalization (#5666)
# Objective

- Morten Mikkelsen clarified that the world normal and tangent must be normalized in the vertex stage and the interpolated values must not be normalized in the fragment stage. This is in order to match the mikktspace approach exactly.
- Fixes #5514 by ensuring the tangent basis matrix (TBN) is orthonormal

## Solution

- Normalize the world normal in the vertex stage and not the fragment stage
- Normalize the world tangent xyz in the vertex stage
- Take into account the sign of the determinant of the local to world matrix when calculating the bitangent

---

## Changelog

- Fixed - scaling a model that uses normal mapping now has correct lighting again
2022-08-18 21:54:40 +00:00
ira
992681b59b Make Resource trait opt-in, requiring #[derive(Resource)] V2 (#5577)
*This PR description is an edited copy of #5007, written by @alice-i-cecile.*
# Objective
Follow-up to https://github.com/bevyengine/bevy/pull/2254. The `Resource` trait currently has a blanket implementation for all types that meet its bounds.

While ergonomic, this results in several drawbacks:

* it is possible to make confusing, silent mistakes such as inserting a function pointer (Foo) rather than a value (Foo::Bar) as a resource
* it is challenging to discover if a type is intended to be used as a resource
* we cannot later add customization options (see the [RFC](https://github.com/bevyengine/rfcs/blob/main/rfcs/27-derive-component.md) for the equivalent choice for Component).
* dependencies can use the same Rust type as a resource in invisibly conflicting ways
* raw Rust types used as resources cannot preserve privacy appropriately, as anyone able to access that type can read and write to internal values
* we cannot capture a definitive list of possible resources to display to users in an editor
## Notes to reviewers
 * Review this commit-by-commit; there's effectively no back-tracking and there's a lot of churn in some of these commits.
   *ira: My commits are not as well organized :')*
 * I've relaxed the bound on Local to Send + Sync + 'static: I don't think these concerns apply there, so this can keep things simple. Storing e.g. a u32 in a Local is fine, because there's a variable name attached explaining what it does.
 * I think this is a bad place for the Resource trait to live, but I've left it in place to make reviewing easier. IMO that's best tackled with https://github.com/bevyengine/bevy/issues/4981.

## Changelog
`Resource` is no longer automatically implemented for all matching types. Instead, use the new `#[derive(Resource)]` macro.

## Migration Guide
Add `#[derive(Resource)]` to all types you are using as a resource.

If you are using a third party type as a resource, wrap it in a tuple struct to bypass orphan rules. Consider deriving `Deref` and `DerefMut` to improve ergonomics.

`ClearColor` no longer implements `Component`. Using `ClearColor` as a component in 0.8 did nothing.
Use the `ClearColorConfig` in the `Camera3d` and `Camera2d` components instead.


Co-authored-by: Alice <alice.i.cecile@gmail.com>
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: devil-ira <justthecooldude@gmail.com>
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2022-08-08 21:36:35 +00:00
Timo Kösters
2ac744331b Fix shader syntax (#5613) 2022-08-08 19:59:59 +00:00
github-actions[bot]
444150025d Bump Version after Release (#5576)
Bump version after release
This PR has been auto-generated
2022-08-05 02:03:05 +00:00
Josh Stratton
a9cb18eefc add default direction to DirectionalLight docs (#5188)
# Objective

- Adds a default direction to the documentation of DirectionalLight 

## Solution

Suggestion from Q&A answer: 
https://github.com/bevyengine/bevy/discussions/5186#discussioncomment-3073767
2022-08-02 18:13:21 +00:00
github-actions[bot]
856588ed7c Release 0.8.0 (#5490)
Preparing next release
This PR has been auto-generated
2022-07-30 14:07:30 +00:00
robtfm
6a1ba9c456 Spotlight shadow bugfix (#5451)
# Objective

fix an error in shadow map indexing that occurs when point lights without shadows are used in conjunction with spotlights with shadows

## Solution

calculate point_light_count correctly
2022-07-25 16:24:54 +00:00
Nicola Papale
4b1f6f4ebb Add some documentation to standard material fields (#5323)
# Objective

the bevy pbr shader doesn't handle at all normal maps
if a mesh doesn't have backed tangents. This is a pitfall
(that I fell into) and needs to be documented.

# Solution

Document the behavior. (Also document a few other
`StandardMaterial` fields)

## Changelog

* Add documentation to `emissive`, `normal_map_texture` and `occlusion_texture` fields of `StandardMaterial`.
2022-07-20 22:00:59 +00:00
Christopher Biscardi
d4f8f88bb6 Don't panic when StandardMaterial normal_map hasn't loaded yet (#5307)
# Objective

[This unwrap()](de484c1e41/crates/bevy_pbr/src/pbr_material.rs (L195)) in pbr_material.rs will be hit if a StandardMaterial normal_map image has not finished loading, resulting in an error message that is hard to debug.

## Solution

~~This PR improves the error message including a potential indication of why the unwrap() could have panic'd by using expect() instead of unwrap().~~

This PR removes the panic by only proceeding if the image is found.

---

## Changelog

Don't panic when StandardMaterial normal_map images have not finished loading.
2022-07-16 21:50:19 +00:00
Dusty DeWeese
9f8bdeeeb9 Use Affine3A for GlobalTransform to allow any affine transformation (#4379)
# Objective

- Add capability to use `Affine3A`s for some `GlobalTransform`s. This allows affine transformations that are not possible using a single `Transform` such as shear and non-uniform scaling along an arbitrary axis.
- Related to #1755 and #2026

## Solution

- `GlobalTransform` becomes an enum wrapping either a `Transform` or an `Affine3A`.
- The API of `GlobalTransform` is minimized to avoid inefficiency, and to make it clear that operations should be performed using the underlying data types.
- using `GlobalTransform::Affine3A` disables transform propagation, because the main use is for cases that `Transform`s cannot support.

---

## Changelog

- `GlobalTransform`s can optionally support any affine transformation using an `Affine3A`.


Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2022-07-16 00:51:12 +00:00
Carter Anderson
40d4992401 Visibilty Inheritance, universal ComputedVisibility and RenderLayers support (#5310)
# Objective

Fixes #4907. Fixes #838. Fixes #5089.
Supersedes #5146. Supersedes #2087. Supersedes #865. Supersedes #5114

Visibility is currently entirely local. Set a parent entity to be invisible, and the children are still visible. This makes it hard for users to hide entire hierarchies of entities.

Additionally, the semantics of `Visibility` vs `ComputedVisibility` are inconsistent across entity types. 3D meshes use `ComputedVisibility` as the "definitive" visibility component, with `Visibility` being just one data source. Sprites just use `Visibility`, which means they can't feed off of `ComputedVisibility` data, such as culling information, RenderLayers, and (added in this pr) visibility inheritance information.

## Solution

Splits `ComputedVisibilty::is_visible` into `ComputedVisibilty::is_visible_in_view` and `ComputedVisibilty::is_visible_in_hierarchy`. For each visible entity, `is_visible_in_hierarchy` is computed by propagating visibility down the hierarchy. The `ComputedVisibility::is_visible()` function combines these two booleans for the canonical "is this entity visible" function.

Additionally, all entities that have `Visibility` now also have `ComputedVisibility`.  Sprites, Lights, and UI entities now use `ComputedVisibility` when appropriate.

This means that in addition to visibility inheritance, everything using Visibility now also supports RenderLayers. Notably, Sprites (and other 2d objects) now support `RenderLayers` and work properly across multiple views.

Also note that this does increase the amount of work done per sprite. Bevymark with 100,000 sprites on `main` runs in `0.017612` seconds and this runs in `0.01902`. That is certainly a gap, but I believe the api consistency and extra functionality this buys us is worth it. See [this thread](https://github.com/bevyengine/bevy/pull/5146#issuecomment-1182783452) for more info. Note that #5146 in combination with #5114 _are_ a viable alternative to this PR and _would_ perform better, but that comes at the cost of api inconsistencies and doing visibility calculations in the "wrong" place. The current visibility system does have potential for performance improvements. I would prefer to evolve that one system as a whole rather than doing custom hacks / different behaviors for each feature slice.

Here is a "split screen" example where the left camera uses RenderLayers to filter out the blue sprite.

![image](https://user-images.githubusercontent.com/2694663/178814868-2e9a2173-bf8c-4c79-8815-633899d492c3.png)


Note that this builds directly on #5146 and that @james7132 deserves the credit for the baseline visibility inheritance work. This pr moves the inherited visibility field into `ComputedVisibility`, then does the additional work of porting everything to `ComputedVisibility`. See my [comments here](https://github.com/bevyengine/bevy/pull/5146#issuecomment-1182783452) for rationale. 

## Follow up work

* Now that lights use ComputedVisibility, VisibleEntities now includes "visible lights" in the entity list. Functionally not a problem as we use queries to filter the list down in the desired context. But we should consider splitting this out into a separate`VisibleLights` collection for both clarity and performance reasons. And _maybe_ even consider scoping `VisibleEntities` down to `VisibleMeshes`?.
* Investigate alternative sprite rendering impls (in combination with visibility system tweaks) that avoid re-generating a per-view fixedbitset of visible entities every frame, then checking each ExtractedEntity. This is where most of the performance overhead lives. Ex: we could generate ExtractedEntities per-view using the VisibleEntities list, avoiding the need for the bitset.
* Should ComputedVisibility use bitflags under the hood? This would cut down on the size of the component, potentially speed up the `is_visible()` function, and allow us to cheaply expand ComputedVisibility with more data (ex: split out local visibility and parent visibility, add more culling classes, etc).
---

## Changelog

* ComputedVisibility now takes hierarchy visibility into account.
* 2D, UI and Light entities now use the ComputedVisibility component.

## Migration Guide

If you were previously reading `Visibility::is_visible` as the "actual visibility" for sprites or lights, use `ComputedVisibilty::is_visible()` instead:

```rust
// before (0.7)
fn system(query: Query<&Visibility>) {
  for visibility in query.iter() {
    if visibility.is_visible {
       log!("found visible entity");
    }
  }
}

// after (0.8)
fn system(query: Query<&ComputedVisibility>) {
  for visibility in query.iter() {
    if visibility.is_visible() {
       log!("found visible entity");
    }
  }
}
``` 


Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2022-07-15 23:24:42 +00:00
François
814f8d1635 update wgpu to 0.13 (#5168)
# Objective

- Update wgpu to 0.13
- ~~Wait, is wgpu 0.13 released? No, but I had most of the changes already ready since playing with webgpu~~ well it has been released now
- Also update parking_lot to 0.12 and naga to 0.9

## Solution

- Update syntax for wgsl shaders https://github.com/gfx-rs/wgpu/blob/master/CHANGELOG.md#wgsl-syntax
- Add a few options, remove some references: https://github.com/gfx-rs/wgpu/blob/master/CHANGELOG.md#other-breaking-changes
- fragment inputs should now exactly match vertex outputs for locations, so I added exports for those to be able to reuse them https://github.com/gfx-rs/wgpu/pull/2704
2022-07-14 21:17:16 +00:00