222483daaa
35 Commits
Author | SHA1 | Message | Date | |
---|---|---|---|---|
![]() |
222483daaa
|
Adding alpha_threshold to OrderIndependentTransparencySettings for user-level optimization (#16090)
# Objective Order independent transparency can filter fragment writes based on the alpha value and it is currently hard-coded to anything higher than 0.0. By making that value configurable, users can optimize fragment writes, potentially reducing the number of layers needed and improving performance in favor of some transparency quality. ## Solution This PR adds `alpha_threshold` to the OrderIndependentTransparencySettings component and uses the struct to configure a corresponding shader uniform. This uniform is then used instead of the hard-coded value. To configure OIT with a custom alpha threshold, use: ```rust fn setup(mut commands: Commands) { commands.spawn(( Camera3d::default(), OrderIndependentTransparencySettings { layer_count: 8, alpha_threshold: 0.2, }, )); } ``` ## Testing I tested this change using the included OIT example, as well as with two additional projects. ## Migration Guide If you previously explicitly initialized OrderIndependentTransparencySettings with your own `layer_count`, you will now have to add either a `..default()` statement or an explicit `alpha_threshold` value: ```rust fn setup(mut commands: Commands) { commands.spawn(( Camera3d::default(), OrderIndependentTransparencySettings { layer_count: 16, ..default() }, )); } ``` --------- Co-authored-by: JMS55 <47158642+JMS55@users.noreply.github.com> |
||
![]() |
dcca983c25
|
Place percentage-closer soft shadows behind a feature gate to save on samplers. (#16068)
The two additional linear texture samplers that PCSS added caused us to blow past the limit on Apple Silicon macOS and WebGL. To fix the issue, this commit adds a `--feature pbr_pcss` feature gate that disables PCSS if not present. Closes #15345. Closes #15525. Closes #15821. --------- Co-authored-by: Carter Anderson <mcanders1@gmail.com> Co-authored-by: IceSentry <IceSentry@users.noreply.github.com> |
||
![]() |
b48f9e2a4b
|
Fix oit webgl (#15728)
The previous fixes were breaking pretty much everything on main due to naga-oil complaining about the OIT shader not being loaded, since apparently webgl is a default feature. This fix is a bit messier, but properly warns the user and is probably what we should have gone for in the first place. |
||
![]() |
4bf647ff3b
|
Add Order Independent Transparency (#14876)
# Objective - Alpha blending can easily fail in many situations and requires sorting on the cpu ## Solution - Implement order independent transparency (OIT) as an alternative to alpha blending - The implementation uses 2 passes - The first pass records all the fragments colors and position to a buffer that is the size of N layers * the render target resolution. - The second pass sorts the fragments, blends them and draws them to the screen. It also currently does manual depth testing because early-z fails in too many cases in the first pass. ## Testing - We've been using this implementation at foresight in production for many months now and we haven't had any issues related to OIT. --- ## Showcase   ## Future work - Add an example showing how to use OIT for a custom material - Next step would be to implement a per-pixel linked list to reduce memory use - I'd also like to investigate using a BinnedRenderPhase instead of a SortedRenderPhase. If it works, it would make the transparent pass significantly faster. --------- Co-authored-by: Kristoffer Søholm <k.soeholm@gmail.com> Co-authored-by: JMS55 <47158642+JMS55@users.noreply.github.com> Co-authored-by: Charlotte McElwain <charlotte.c.mcelwain@gmail.com> |
||
![]() |
ba7907cae7
|
Added visibility bitmask as an alternative SSAO method (#13454)
Early implementation. I still have to fix the documentation and consider writing a small migration guide. Questions left to answer: * [x] should thickness be an overridable constant? * [x] is there a better way to implement `Eq`/`Hash` for `SSAOMethod`? * [x] do we want to keep the linear sampler for the depth texture? * [x] is there a better way to separate the logic than preprocessor macros?  ## Migration guide SSAO algorithm was changed from GTAO to VBAO (visibility bitmasks). A new field, `constant_object_thickness`, was added to `ScreenSpaceAmbientOcclusion`. `ScreenSpaceAmbientOcclusion` also lost its `Eq` and `Hash` implementations. --------- Co-authored-by: JMS55 <47158642+JMS55@users.noreply.github.com> |
||
![]() |
d70595b667
|
Add core and alloc over std Lints (#15281)
# Objective - Fixes #6370 - Closes #6581 ## Solution - Added the following lints to the workspace: - `std_instead_of_core` - `std_instead_of_alloc` - `alloc_instead_of_core` - Used `cargo +nightly fmt` with [item level use formatting](https://rust-lang.github.io/rustfmt/?version=v1.6.0&search=#Item%5C%3A) to split all `use` statements into single items. - Used `cargo clippy --workspace --all-targets --all-features --fix --allow-dirty` to _attempt_ to resolve the new linting issues, and intervened where the lint was unable to resolve the issue automatically (usually due to needing an `extern crate alloc;` statement in a crate root). - Manually removed certain uses of `std` where negative feature gating prevented `--all-features` from finding the offending uses. - Used `cargo +nightly fmt` with [crate level use formatting](https://rust-lang.github.io/rustfmt/?version=v1.6.0&search=#Crate%5C%3A) to re-merge all `use` statements matching Bevy's previous styling. - Manually fixed cases where the `fmt` tool could not re-merge `use` statements due to conditional compilation attributes. ## Testing - Ran CI locally ## Migration Guide The MSRV is now 1.81. Please update to this version or higher. ## Notes - This is a _massive_ change to try and push through, which is why I've outlined the semi-automatic steps I used to create this PR, in case this fails and someone else tries again in the future. - Making this change has no impact on user code, but does mean Bevy contributors will be warned to use `core` and `alloc` instead of `std` where possible. - This lint is a critical first step towards investigating `no_std` options for Bevy. --------- Co-authored-by: François Mockers <francois.mockers@vleue.com> |
||
![]() |
2ae5a21009
|
Implement percentage-closer soft shadows (PCSS). (#13497)
[*Percentage-closer soft shadows*] are a technique from 2004 that allow shadows to become blurrier farther from the objects that cast them. It works by introducing a *blocker search* step that runs before the normal shadow map sampling. The blocker search step detects the difference between the depth of the fragment being rasterized and the depth of the nearby samples in the depth buffer. Larger depth differences result in a larger penumbra and therefore a blurrier shadow. To enable PCSS, fill in the `soft_shadow_size` value in `DirectionalLight`, `PointLight`, or `SpotLight`, as appropriate. This shadow size value represents the size of the light and should be tuned as appropriate for your scene. Higher values result in a wider penumbra (i.e. blurrier shadows). When using PCSS, temporal shadow maps (`ShadowFilteringMethod::Temporal`) are recommended. If you don't use `ShadowFilteringMethod::Temporal` and instead use `ShadowFilteringMethod::Gaussian`, Bevy will use the same technique as `Temporal`, but the result won't vary over time. This produces a rather noisy result. Doing better would likely require downsampling the shadow map, which would be complex and slower (and would require PR #13003 to land first). In addition to PCSS, this commit makes the near Z plane for the shadow map configurable on a per-light basis. Previously, it had been hardcoded to 0.1 meters. This change was necessary to make the point light shadow map in the example look reasonable, as otherwise the shadows appeared far too aliased. A new example, `pcss`, has been added. It demonstrates the percentage-closer soft shadow technique with directional lights, point lights, spot lights, non-temporal operation, and temporal operation. The assets are my original work. Both temporal and non-temporal shadows are rather noisy in the example, and, as mentioned before, this is unavoidable without downsampling the depth buffer, which we can't do yet. Note also that the shadows don't look particularly great for point lights; the example simply isn't an ideal scene for them. Nevertheless, I felt that the benefits of the ability to do a side-by-side comparison of directional and point lights outweighed the unsightliness of the point light shadows in that example, so I kept the point light feature in. Fixes #3631. [*Percentage-closer soft shadows*]: https://developer.download.nvidia.com/shaderlibrary/docs/shadow_PCSS.pdf ## Changelog ### Added * Percentage-closer soft shadows (PCSS) are now supported, allowing shadows to become blurrier as they stretch away from objects. To use them, set the `soft_shadow_size` field in `DirectionalLight`, `PointLight`, or `SpotLight`, as applicable. * The near Z value for shadow maps is now customizable via the `shadow_map_near_z` field in `DirectionalLight`, `PointLight`, and `SpotLight`. ## Screenshots PCSS off:  PCSS on:  --------- Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com> Co-authored-by: Torstein Grindvik <52322338+torsteingrindvik@users.noreply.github.com> |
||
![]() |
bc13161416
|
Migrated NonZero* to NonZero<*> (#14978)
# Objective - Fixes #14974 ## Solution - Replace all* instances of `NonZero*` with `NonZero<*>` ## Testing - CI passed locally. --- ## Notes Within the `bevy_reflect` implementations for `std` types, `impl_reflect_value!()` will continue to use the type aliases instead, as it inappropriately parses the concrete type parameter as a generic argument. If the `ZeroablePrimitive` trait was stable, or the macro could be modified to accept a finite list of types, then we could fully migrate. |
||
![]() |
03fd1b46ef
|
Move Msaa to component (#14273)
Switches `Msaa` from being a globally configured resource to a per camera view component. Closes #7194 # Objective Allow individual views to describe their own MSAA settings. For example, when rendering to different windows or to different parts of the same view. ## Solution Make `Msaa` a component that is required on all camera bundles. ## Testing Ran a variety of examples to ensure that nothing broke. TODO: - [ ] Make sure android still works per previous comment in `extract_windows`. --- ## Migration Guide `Msaa` is no longer configured as a global resource, and should be specified on each spawned camera if a non-default setting is desired. --------- Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com> Co-authored-by: François Mockers <francois.mockers@vleue.com> |
||
![]() |
9da18cce2a
|
Add support for environment map transformation (#14290)
# Objective - Fixes: https://github.com/bevyengine/bevy/issues/14036 ## Solution - Add a world space transformation for the environment sample direction. ## Testing - I have tested the newly added `transform` field using the newly added `rotate_environment_map` example. https://github.com/user-attachments/assets/2de77c65-14bc-48ee-b76a-fb4e9782dbdb ## Migration Guide - Since we have added a new filed to the `EnvironmentMapLight` struct, users will need to include `..default()` or some rotation value in their initialization code. |
||
![]() |
ad6872275f
|
Rename "point light" to "clusterable object" in cluster contexts. (#13654)
We want to use the clustering infrastructure for light probes and decals as well, not just point lights. This patch builds on top of #13640 and performs the rename. To make this series easier to review, this patch makes no code changes. Only identifiers and comments are modified. ## Migration Guide * In the PBR shaders, `point_lights` is now known as `clusterable_objects`, `PointLight` is now known as `ClusterableObject`, and `cluster_light_index_lists` is now known as `clusterable_object_index_lists`. |
||
![]() |
f398674e51
|
Implement opt-in sharp screen-space reflections for the deferred renderer, with improved raymarching code. (#13418)
This commit, a revamp of #12959, implements screen-space reflections (SSR), which approximate real-time reflections based on raymarching through the depth buffer and copying samples from the final rendered frame. This patch is a relatively minimal implementation of SSR, so as to provide a flexible base on which to customize and build in the future. However, it's based on the production-quality [raymarching code by Tomasz Stachowiak](https://gist.github.com/h3r2tic/9c8356bdaefbe80b1a22ae0aaee192db). For a general basic overview of screen-space reflections, see [1](https://lettier.github.io/3d-game-shaders-for-beginners/screen-space-reflection.html). The raymarching shader uses the basic algorithm of tracing forward in large steps, refining that trace in smaller increments via binary search, and then using the secant method. No temporal filtering or roughness blurring, is performed at all; for this reason, SSR currently only operates on very shiny surfaces. No acceleration via the hierarchical Z-buffer is implemented (though note that https://github.com/bevyengine/bevy/pull/12899 will add the infrastructure for this). Reflections are traced at full resolution, which is often considered slow. All of these improvements and more can be follow-ups. SSR is built on top of the deferred renderer and is currently only supported in that mode. Forward screen-space reflections are possible albeit uncommon (though e.g. *Doom Eternal* uses them); however, they require tracing from the previous frame, which would add complexity. This patch leaves the door open to implementing SSR in the forward rendering path but doesn't itself have such an implementation. Screen-space reflections aren't supported in WebGL 2, because they require sampling from the depth buffer, which Naga can't do because of a bug (`sampler2DShadow` is incorrectly generated instead of `sampler2D`; this is the same reason why depth of field is disabled on that platform). To add screen-space reflections to a camera, use the `ScreenSpaceReflectionsBundle` bundle or the `ScreenSpaceReflectionsSettings` component. In addition to `ScreenSpaceReflectionsSettings`, `DepthPrepass` and `DeferredPrepass` must also be present for the reflections to show up. The `ScreenSpaceReflectionsSettings` component contains several settings that artists can tweak, and also comes with sensible defaults. A new example, `ssr`, has been added. It's loosely based on the [three.js ocean sample](https://threejs.org/examples/webgl_shaders_ocean.html), but all the assets are original. Note that the three.js demo has no screen-space reflections and instead renders a mirror world. In contrast to #12959, this demo tests not only a cube but also a more complex model (the flight helmet). ## Changelog ### Added * Screen-space reflections can be enabled for very smooth surfaces by adding the `ScreenSpaceReflections` component to a camera. Deferred rendering must be enabled for the reflections to appear.   |
||
![]() |
bf2aced279
|
Remove another .view_layouts (#13410)
I forgot to save that file when submitting #13394 😅 |
||
![]() |
19bfa41768
|
Implement volumetric fog and volumetric lighting, also known as light shafts or god rays. (#13057)
This commit implements a more physically-accurate, but slower, form of fog than the `bevy_pbr::fog` module does. Notably, this *volumetric fog* allows for light beams from directional lights to shine through, creating what is known as *light shafts* or *god rays*. To add volumetric fog to a scene, add `VolumetricFogSettings` to the camera, and add `VolumetricLight` to directional lights that you wish to be volumetric. `VolumetricFogSettings` has numerous settings that allow you to define the accuracy of the simulation, as well as the look of the fog. Currently, only interaction with directional lights that have shadow maps is supported. Note that the overhead of the effect scales directly with the number of directional lights in use, so apply `VolumetricLight` sparingly for the best results. The overall algorithm, which is implemented as a postprocessing effect, is a combination of the techniques described in [Scratchapixel] and [this blog post]. It uses raymarching in screen space, transformed into shadow map space for sampling and combined with physically-based modeling of absorption and scattering. Bevy employs the widely-used [Henyey-Greenstein phase function] to model asymmetry; this essentially allows light shafts to fade into and out of existence as the user views them. Volumetric rendering is a huge subject, and I deliberately kept the scope of this commit small. Possible follow-ups include: 1. Raymarching at a lower resolution. 2. A post-processing blur (especially useful when combined with (1)). 3. Supporting point lights and spot lights. 4. Supporting lights with no shadow maps. 5. Supporting irradiance volumes and reflection probes. 6. Voxel components that reuse the volumetric fog code to create voxel shapes. 7. *Horizon: Zero Dawn*-style clouds. These are all useful, but out of scope of this patch for now, to keep things tidy and easy to review. A new example, `volumetric_fog`, has been added to demonstrate the effect. ## Changelog ### Added * A new component, `VolumetricFog`, is available, to allow for a more physically-accurate, but more resource-intensive, form of fog. * A new component, `VolumetricLight`, can be placed on directional lights to make them interact with `VolumetricFog`. Notably, this allows such lights to emit light shafts/god rays.   [Scratchapixel]: https://www.scratchapixel.com/lessons/3d-basic-rendering/volume-rendering-for-developers/intro-volume-rendering.html [this blog post]: https://www.alexandre-pestana.com/volumetric-lights/ [Henyey-Greenstein phase function]: https://www.pbr-book.org/4ed/Volume_Scattering/Phase_Functions#TheHenyeyndashGreensteinPhaseFunction |
||
![]() |
173db7726f
|
remove unused warnings in release (#13344)
# Objective - When building for release, there are "unused" warnings: ``` warning: unused import: `bevy_utils::warn_once` --> crates/bevy_pbr/src/render/mesh_view_bindings.rs:32:5 | 32 | use bevy_utils::warn_once; | ^^^^^^^^^^^^^^^^^^^^^ | = note: `#[warn(unused_imports)]` on by default warning: unused variable: `texture_count` --> crates/bevy_pbr/src/render/mesh_view_bindings.rs:371:17 | 371 | let texture_count: usize = entries | ^^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_texture_count` | = note: `#[warn(unused_variables)]` on by default ``` ## Solution - Gate the import and definition by the same cfg as their uses |
||
![]() |
4737106bdd
|
Extract mesh view layouts logic (#13266)
Copied almost verbatim from the volumetric fog PR # Objective - Managing mesh view layouts is complicated ## Solution - Extract it to it's own struct - This was done as part of #13057 and is copied almost verbatim. I wanted to keep this part of the PR it's own atomic commit in case we ever have to revert fog or run a bisect. This change is good whether or not we have volumetric fog. Co-Authored-By: @pcwalton |
||
![]() |
31835ff76d
|
Implement visibility ranges, also known as hierarchical levels of detail (HLODs). (#12916)
Implement visibility ranges, also known as hierarchical levels of detail (HLODs). This commit introduces a new component, `VisibilityRange`, which allows developers to specify camera distances in which meshes are to be shown and hidden. Hiding meshes happens early in the rendering pipeline, so this feature can be used for level of detail optimization. Additionally, this feature is properly evaluated per-view, so different views can show different levels of detail. This feature differs from proper mesh LODs, which can be implemented later. Engines generally implement true mesh LODs later in the pipeline; they're typically more efficient than HLODs with GPU-driven rendering. However, mesh LODs are more limited than HLODs, because they require the lower levels of detail to be meshes with the same vertex layout and shader (and perhaps the same material) as the original mesh. Games often want to use objects other than meshes to replace distant models, such as *octahedral imposters* or *billboard imposters*. The reason why the feature is called *hierarchical level of detail* is that HLODs can replace multiple meshes with a single mesh when the camera is far away. This can be useful for reducing drawcall count. Note that `VisibilityRange` doesn't automatically propagate down to children; it must be placed on every mesh. Crossfading between different levels of detail is supported, using the standard 4x4 ordered dithering pattern from [1]. The shader code to compute the dithering patterns should be well-optimized. The dithering code is only active when visibility ranges are in use for the mesh in question, so that we don't lose early Z. Cascaded shadow maps show the HLOD level of the view they're associated with. Point light and spot light shadow maps, which have no CSMs, display all HLOD levels that are visible in any view. To support this efficiently and avoid doing visibility checks multiple times, we precalculate all visible HLOD levels for each entity with a `VisibilityRange` during the `check_visibility_range` system. A new example, `visibility_range`, has been added to the tree, as well as a new low-poly version of the flight helmet model to go with it. It demonstrates use of the visibility range feature to provide levels of detail. [1]: https://en.wikipedia.org/wiki/Ordered_dithering#Threshold_map [^1]: Unreal doesn't have a feature that exactly corresponds to visibility ranges, but Unreal's HLOD system serves roughly the same purpose. ## Changelog ### Added * A new `VisibilityRange` component is available to conditionally enable entity visibility at camera distances, with optional crossfade support. This can be used to implement different levels of detail (LODs). ## Screenshots High-poly model:  Low-poly model up close:  Crossfading between the two:  --------- Co-authored-by: Carter Anderson <mcanders1@gmail.com> |
||
![]() |
ab7cbfa8fc
|
Consolidate Render(Ui)Materials(2d) into RenderAssets (#12827)
# Objective - Replace `RenderMaterials` / `RenderMaterials2d` / `RenderUiMaterials` with `RenderAssets` to enable implementing changes to one thing, `RenderAssets`, that applies to all use cases rather than duplicating changes everywhere for multiple things that should be one thing. - Adopts #8149 ## Solution - Make RenderAsset generic over the destination type rather than the source type as in #8149 - Use `RenderAssets<PreparedMaterial<M>>` etc for render materials --- ## Changelog - Changed: - The `RenderAsset` trait is now implemented on the destination type. Its `SourceAsset` associated type refers to the type of the source asset. - `RenderMaterials`, `RenderMaterials2d`, and `RenderUiMaterials` have been replaced by `RenderAssets<PreparedMaterial<M>>` and similar. ## Migration Guide - `RenderAsset` is now implemented for the destination type rather that the source asset type. The source asset type is now the `RenderAsset` trait's `SourceAsset` associated type. |
||
![]() |
452821dd52
|
more robust gpu image use (#12606)
# Objective make morph targets and tonemapping more tolerant of delayed image loading. neither of these actually fail currently unless using a bespoke loader (and even then it would be rare), but i am working on adding throttling for asset gpu uploads (as a stopgap until we can do proper asset streaming) and they break with that. ## Solution when a mesh with morph targets is uploaded to the gpu, the prepare function uploads the morph target texture if it's available, otherwise it uploads without morph targets. this is generally fine as long as morph targets are typically loaded from bytes (in gltf loader), but may fail for a custom loader if the asset server async-loads the target texture and the texture is not available yet. the mesh fails to render and doesn't update when the image is loaded -> if morph targets are specified but not ready yet, retry mesh upload next frame tonemapping `unwrap`s on the lookup table image. this is never a problem since the image is added via `include_bytes!`, but could be a problem in future with asset gpu throttling/streaming. -> if the lookup texture is not yet available, use a fallback -> in the node, check if the fallback was used before caching the bind group |
||
![]() |
5f8f3b532c
|
Check cfg during CI and fix feature typos (#12103)
# Objective - Add the new `-Zcheck-cfg` checks to catch more warnings - Fixes #12091 ## Solution - Create a new `cfg-check` to the CI that runs `cargo check -Zcheck-cfg --workspace` using cargo nightly (and fails if there are warnings) - Fix all warnings generated by the new check --- ## Changelog - Remove all redundant imports - Fix cfg wasm32 targets - Add 3 dead code exceptions (should StandardColor be unused?) - Convert ios_simulator to a feature (I'm not sure if this is the right way to do it, but the check complained before) ## Migration Guide No breaking changes --------- Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com> |
||
![]() |
caa7ec68d4
|
FIX: iOS Simulator not rendering due to missing CUBE_ARRAY_TEXTURES (#12052)
This PR closes #11978 # Objective Fix rendering on iOS Simulators. iOS Simulator doesn't support the capability CUBE_ARRAY_TEXTURES, since 0.13 this started to make iOS Simulator not render anything with the following message being outputted: ``` 2024-02-19T14:59:34.896266Z ERROR bevy_render::render_resource::pipeline_cache: failed to create shader module: Validation Error Caused by: In Device::create_shader_module Shader validation error: Type [40] '' is invalid Capability Capabilities(CUBE_ARRAY_TEXTURES) is required ``` ## Solution - Split up NO_ARRAY_TEXTURES_SUPPORT into both NO_ARRAY_TEXTURES_SUPPORT and NO_CUBE_ARRAY_TEXTURES_SUPPORT and correctly apply NO_ARRAY_TEXTURES_SUPPORT for iOS Simulator using the cfg flag introduced in #10178. --- ## Changelog ### Fixed - Rendering on iOS Simulator due to missing CUBE_ARRAY_TEXTURES support. --------- Co-authored-by: Sam Pettersson <sam.pettersson@geoguessr.com> |
||
![]() |
a513493dcc
|
Make Globals visible in vertex shaders (#12032)
# Objective - Globals are supposed to be available in vertex shader but that was mistakenly removed in 0.13 ## Solution - Configure the visibility of the globals correctly Fixes https://github.com/bevyengine/bevy/issues/12015 |
||
![]() |
3058c17d6a
|
Disable irradiance volumes on WebGL and WebGPU. (#11909)
They cause the number of texture bindings to overflow on those platforms. Ultimately, we shouldn't unconditionally disable them, but this fixes a crash blocking 0.13. Closes #11885. |
||
![]() |
4c15dd0fc5
|
Implement irradiance volumes. (#10268)
# Objective Bevy could benefit from *irradiance volumes*, also known as *voxel global illumination* or simply as light probes (though this term is not preferred, as multiple techniques can be called light probes). Irradiance volumes are a form of baked global illumination; they work by sampling the light at the centers of each voxel within a cuboid. At runtime, the voxels surrounding the fragment center are sampled and interpolated to produce indirect diffuse illumination. ## Solution This is divided into two sections. The first is copied and pasted from the irradiance volume module documentation and describes the technique. The second part consists of notes on the implementation. ### Overview An *irradiance volume* is a cuboid voxel region consisting of regularly-spaced precomputed samples of diffuse indirect light. They're ideal if you have a dynamic object such as a character that can move about static non-moving geometry such as a level in a game, and you want that dynamic object to be affected by the light bouncing off that static geometry. To use irradiance volumes, you need to precompute, or *bake*, the indirect light in your scene. Bevy doesn't currently come with a way to do this. Fortunately, [Blender] provides a [baking tool] as part of the Eevee renderer, and its irradiance volumes are compatible with those used by Bevy. The [`bevy-baked-gi`] project provides a tool, `export-blender-gi`, that can extract the baked irradiance volumes from the Blender `.blend` file and package them up into a `.ktx2` texture for use by the engine. See the documentation in the `bevy-baked-gi` project for more details as to this workflow. Like all light probes in Bevy, irradiance volumes are 1×1×1 cubes that can be arbitrarily scaled, rotated, and positioned in a scene with the [`bevy_transform::components::Transform`] component. The 3D voxel grid will be stretched to fill the interior of the cube, and the illumination from the irradiance volume will apply to all fragments within that bounding region. Bevy's irradiance volumes are based on Valve's [*ambient cubes*] as used in *Half-Life 2* ([Mitchell 2006], slide 27). These encode a single color of light from the six 3D cardinal directions and blend the sides together according to the surface normal. The primary reason for choosing ambient cubes is to match Blender, so that its Eevee renderer can be used for baking. However, they also have some advantages over the common second-order spherical harmonics approach: ambient cubes don't suffer from ringing artifacts, they are smaller (6 colors for ambient cubes as opposed to 9 for spherical harmonics), and evaluation is faster. A smaller basis allows for a denser grid of voxels with the same storage requirements. If you wish to use a tool other than `export-blender-gi` to produce the irradiance volumes, you'll need to pack the irradiance volumes in the following format. The irradiance volume of resolution *(Rx, Ry, Rz)* is expected to be a 3D texture of dimensions *(Rx, 2Ry, 3Rz)*. The unnormalized texture coordinate *(s, t, p)* of the voxel at coordinate *(x, y, z)* with side *S* ∈ *{-X, +X, -Y, +Y, -Z, +Z}* is as follows: ```text s = x t = y + ⎰ 0 if S ∈ {-X, -Y, -Z} ⎱ Ry if S ∈ {+X, +Y, +Z} ⎧ 0 if S ∈ {-X, +X} p = z + ⎨ Rz if S ∈ {-Y, +Y} ⎩ 2Rz if S ∈ {-Z, +Z} ``` Visually, in a left-handed coordinate system with Y up, viewed from the right, the 3D texture looks like a stacked series of voxel grids, one for each cube side, in this order: | **+X** | **+Y** | **+Z** | | ------ | ------ | ------ | | **-X** | **-Y** | **-Z** | A terminology note: Other engines may refer to irradiance volumes as *voxel global illumination*, *VXGI*, or simply as *light probes*. Sometimes *light probe* refers to what Bevy calls a reflection probe. In Bevy, *light probe* is a generic term that encompasses all cuboid bounding regions that capture indirect illumination, whether based on voxels or not. Note that, if binding arrays aren't supported (e.g. on WebGPU or WebGL 2), then only the closest irradiance volume to the view will be taken into account during rendering. [*ambient cubes*]: https://advances.realtimerendering.com/s2006/Mitchell-ShadingInValvesSourceEngine.pdf [Mitchell 2006]: https://advances.realtimerendering.com/s2006/Mitchell-ShadingInValvesSourceEngine.pdf [Blender]: http://blender.org/ [baking tool]: https://docs.blender.org/manual/en/latest/render/eevee/render_settings/indirect_lighting.html [`bevy-baked-gi`]: https://github.com/pcwalton/bevy-baked-gi ### Implementation notes This patch generalizes light probes so as to reuse as much code as possible between irradiance volumes and the existing reflection probes. This approach was chosen because both techniques share numerous similarities: 1. Both irradiance volumes and reflection probes are cuboid bounding regions. 2. Both are responsible for providing baked indirect light. 3. Both techniques involve presenting a variable number of textures to the shader from which indirect light is sampled. (In the current implementation, this uses binding arrays.) 4. Both irradiance volumes and reflection probes require gathering and sorting probes by distance on CPU. 5. Both techniques require the GPU to search through a list of bounding regions. 6. Both will eventually want to have falloff so that we can smoothly blend as objects enter and exit the probes' influence ranges. (This is not implemented yet to keep this patch relatively small and reviewable.) To do this, we generalize most of the methods in the reflection probes patch #11366 to be generic over a trait, `LightProbeComponent`. This trait is implemented by both `EnvironmentMapLight` (for reflection probes) and `IrradianceVolume` (for irradiance volumes). Using a trait will allow us to add more types of light probes in the future. In particular, I highly suspect we will want real-time reflection planes for mirrors in the future, which can be easily slotted into this framework. ## Changelog > This section is optional. If this was a trivial fix, or has no externally-visible impact, you can delete this section. ### Added * A new `IrradianceVolume` asset type is available for baked voxelized light probes. You can bake the global illumination using Blender or another tool of your choice and use it in Bevy to apply indirect illumination to dynamic objects. |
||
![]() |
35ac1b152e
|
Update to wgpu 0.19 and raw-window-handle 0.6 (#11280)
# Objective Keep core dependencies up to date. ## Solution Update the dependencies. wgpu 0.19 only supports raw-window-handle (rwh) 0.6, so bumping that was included in this. The rwh 0.6 version bump is just the simplest way of doing it. There might be a way we can take advantage of wgpu's new safe surface creation api, but I'm not familiar enough with bevy's window management to untangle it and my attempt ended up being a mess of lifetimes and rustc complaining about missing trait impls (that were implemented). Thanks to @MiniaczQ for the (much simpler) rwh 0.6 version bump code. Unblocks https://github.com/bevyengine/bevy/pull/9172 and https://github.com/bevyengine/bevy/pull/10812 ~~This might be blocked on cpal and oboe updating their ndk versions to 0.8, as they both currently target ndk 0.7 which uses rwh 0.5.2~~ Tested on android, and everything seems to work correctly (audio properly stops when minimized, and plays when re-focusing the app). --- ## Changelog - `wgpu` has been updated to 0.19! The long awaited arcanization has been merged (for more info, see https://gfx-rs.github.io/2023/11/24/arcanization.html), and Vulkan should now be working again on Intel GPUs. - Targeting WebGPU now requires that you add the new `webgpu` feature (setting the `RUSTFLAGS` environment variable to `--cfg=web_sys_unstable_apis` is still required). This feature currently overrides the `webgl2` feature if you have both enabled (the `webgl2` feature is enabled by default), so it is not recommended to add it as a default feature to libraries without putting it behind a flag that allows library users to opt out of it! In the future we plan on supporting wasm binaries that can target both webgl2 and webgpu now that wgpu added support for doing so (see https://github.com/bevyengine/bevy/issues/11505). - `raw-window-handle` has been updated to version 0.6. ## Migration Guide - `bevy_render::instance_index::get_instance_index()` has been removed as the webgl2 workaround is no longer required as it was fixed upstream in wgpu. The `BASE_INSTANCE_WORKAROUND` shaderdef has also been removed. - WebGPU now requires the new `webgpu` feature to be enabled. The `webgpu` feature currently overrides the `webgl2` feature so you no longer need to disable all default features and re-add them all when targeting `webgpu`, but binaries built with both the `webgpu` and `webgl2` features will only target the webgpu backend, and will only work on browsers that support WebGPU. - Places where you conditionally compiled things for webgl2 need to be updated because of this change, eg: - `#[cfg(any(not(feature = "webgl"), not(target_arch = "wasm32")))]` becomes `#[cfg(any(not(feature = "webgl") ,not(target_arch = "wasm32"), feature = "webgpu"))]` - `#[cfg(all(feature = "webgl", target_arch = "wasm32"))]` becomes `#[cfg(all(feature = "webgl", target_arch = "wasm32", not(feature = "webgpu")))]` - `if cfg!(all(feature = "webgl", target_arch = "wasm32"))` becomes `if cfg!(all(feature = "webgl", target_arch = "wasm32", not(feature = "webgpu")))` - `create_texture_with_data` now also takes a `TextureDataOrder`. You can probably just set this to `TextureDataOrder::default()` - `TextureFormat`'s `block_size` has been renamed to `block_copy_size` - See the `wgpu` changelog for anything I might've missed: https://github.com/gfx-rs/wgpu/blob/trunk/CHANGELOG.md --------- Co-authored-by: François <mockersf@gmail.com> |
||
![]() |
83d6600267
|
Implement minimal reflection probes (fixed macOS, iOS, and Android). (#11366)
This pull request re-submits #10057, which was backed out for breaking macOS, iOS, and Android. I've tested this version on macOS and Android and on the iOS simulator. # Objective This pull request implements *reflection probes*, which generalize environment maps to allow for multiple environment maps in the same scene, each of which has an axis-aligned bounding box. This is a standard feature of physically-based renderers and was inspired by [the corresponding feature in Blender's Eevee renderer]. ## Solution This is a minimal implementation of reflection probes that allows artists to define cuboid bounding regions associated with environment maps. For every view, on every frame, a system builds up a list of the nearest 4 reflection probes that are within the view's frustum and supplies that list to the shader. The PBR fragment shader searches through the list, finds the first containing reflection probe, and uses it for indirect lighting, falling back to the view's environment map if none is found. Both forward and deferred renderers are fully supported. A reflection probe is an entity with a pair of components, *LightProbe* and *EnvironmentMapLight* (as well as the standard *SpatialBundle*, to position it in the world). The *LightProbe* component (along with the *Transform*) defines the bounding region, while the *EnvironmentMapLight* component specifies the associated diffuse and specular cubemaps. A frequent question is "why two components instead of just one?" The advantages of this setup are: 1. It's readily extensible to other types of light probes, in particular *irradiance volumes* (also known as ambient cubes or voxel global illumination), which use the same approach of bounding cuboids. With a single component that applies to both reflection probes and irradiance volumes, we can share the logic that implements falloff and blending between multiple light probes between both of those features. 2. It reduces duplication between the existing *EnvironmentMapLight* and these new reflection probes. Systems can treat environment maps attached to cameras the same way they treat environment maps applied to reflection probes if they wish. Internally, we gather up all environment maps in the scene and place them in a cubemap array. At present, this means that all environment maps must have the same size, mipmap count, and texture format. A warning is emitted if this restriction is violated. We could potentially relax this in the future as part of the automatic mipmap generation work, which could easily do texture format conversion as part of its preprocessing. An easy way to generate reflection probe cubemaps is to bake them in Blender and use the `export-blender-gi` tool that's part of the [`bevy-baked-gi`] project. This tool takes a `.blend` file containing baked cubemaps as input and exports cubemap images, pre-filtered with an embedded fork of the [glTF IBL Sampler], alongside a corresponding `.scn.ron` file that the scene spawner can use to recreate the reflection probes. Note that this is intentionally a minimal implementation, to aid reviewability. Known issues are: * Reflection probes are basically unsupported on WebGL 2, because WebGL 2 has no cubemap arrays. (Strictly speaking, you can have precisely one reflection probe in the scene if you have no other cubemaps anywhere, but this isn't very useful.) * Reflection probes have no falloff, so reflections will abruptly change when objects move from one bounding region to another. * As mentioned before, all cubemaps in the world of a given type (diffuse or specular) must have the same size, format, and mipmap count. Future work includes: * Blending between multiple reflection probes. * A falloff/fade-out region so that reflected objects disappear gradually instead of vanishing all at once. * Irradiance volumes for voxel-based global illumination. This should reuse much of the reflection probe logic, as they're both GI techniques based on cuboid bounding regions. * Support for WebGL 2, by breaking batches when reflection probes are used. These issues notwithstanding, I think it's best to land this with roughly the current set of functionality, because this patch is useful as is and adding everything above would make the pull request significantly larger and harder to review. --- ## Changelog ### Added * A new *LightProbe* component is available that specifies a bounding region that an *EnvironmentMapLight* applies to. The combination of a *LightProbe* and an *EnvironmentMapLight* offers *reflection probe* functionality similar to that available in other engines. [the corresponding feature in Blender's Eevee renderer]: https://docs.blender.org/manual/en/latest/render/eevee/light_probes/reflection_cubemaps.html [`bevy-baked-gi`]: https://github.com/pcwalton/bevy-baked-gi [glTF IBL Sampler]: https://github.com/KhronosGroup/glTF-IBL-Sampler |
||
![]() |
3d996639a0
|
Revert "Implement minimal reflection probes. (#10057)" (#11307)
# Objective - Fix working on macOS, iOS, Android on main - Fixes #11281 - Fixes #11282 - Fixes #11283 - Fixes #11299 ## Solution - Revert #10057 |
||
![]() |
54a943d232
|
Implement minimal reflection probes. (#10057)
# Objective This pull request implements *reflection probes*, which generalize environment maps to allow for multiple environment maps in the same scene, each of which has an axis-aligned bounding box. This is a standard feature of physically-based renderers and was inspired by [the corresponding feature in Blender's Eevee renderer]. ## Solution This is a minimal implementation of reflection probes that allows artists to define cuboid bounding regions associated with environment maps. For every view, on every frame, a system builds up a list of the nearest 4 reflection probes that are within the view's frustum and supplies that list to the shader. The PBR fragment shader searches through the list, finds the first containing reflection probe, and uses it for indirect lighting, falling back to the view's environment map if none is found. Both forward and deferred renderers are fully supported. A reflection probe is an entity with a pair of components, *LightProbe* and *EnvironmentMapLight* (as well as the standard *SpatialBundle*, to position it in the world). The *LightProbe* component (along with the *Transform*) defines the bounding region, while the *EnvironmentMapLight* component specifies the associated diffuse and specular cubemaps. A frequent question is "why two components instead of just one?" The advantages of this setup are: 1. It's readily extensible to other types of light probes, in particular *irradiance volumes* (also known as ambient cubes or voxel global illumination), which use the same approach of bounding cuboids. With a single component that applies to both reflection probes and irradiance volumes, we can share the logic that implements falloff and blending between multiple light probes between both of those features. 2. It reduces duplication between the existing *EnvironmentMapLight* and these new reflection probes. Systems can treat environment maps attached to cameras the same way they treat environment maps applied to reflection probes if they wish. Internally, we gather up all environment maps in the scene and place them in a cubemap array. At present, this means that all environment maps must have the same size, mipmap count, and texture format. A warning is emitted if this restriction is violated. We could potentially relax this in the future as part of the automatic mipmap generation work, which could easily do texture format conversion as part of its preprocessing. An easy way to generate reflection probe cubemaps is to bake them in Blender and use the `export-blender-gi` tool that's part of the [`bevy-baked-gi`] project. This tool takes a `.blend` file containing baked cubemaps as input and exports cubemap images, pre-filtered with an embedded fork of the [glTF IBL Sampler], alongside a corresponding `.scn.ron` file that the scene spawner can use to recreate the reflection probes. Note that this is intentionally a minimal implementation, to aid reviewability. Known issues are: * Reflection probes are basically unsupported on WebGL 2, because WebGL 2 has no cubemap arrays. (Strictly speaking, you can have precisely one reflection probe in the scene if you have no other cubemaps anywhere, but this isn't very useful.) * Reflection probes have no falloff, so reflections will abruptly change when objects move from one bounding region to another. * As mentioned before, all cubemaps in the world of a given type (diffuse or specular) must have the same size, format, and mipmap count. Future work includes: * Blending between multiple reflection probes. * A falloff/fade-out region so that reflected objects disappear gradually instead of vanishing all at once. * Irradiance volumes for voxel-based global illumination. This should reuse much of the reflection probe logic, as they're both GI techniques based on cuboid bounding regions. * Support for WebGL 2, by breaking batches when reflection probes are used. These issues notwithstanding, I think it's best to land this with roughly the current set of functionality, because this patch is useful as is and adding everything above would make the pull request significantly larger and harder to review. --- ## Changelog ### Added * A new *LightProbe* component is available that specifies a bounding region that an *EnvironmentMapLight* applies to. The combination of a *LightProbe* and an *EnvironmentMapLight* offers *reflection probe* functionality similar to that available in other engines. [the corresponding feature in Blender's Eevee renderer]: https://docs.blender.org/manual/en/latest/render/eevee/light_probes/reflection_cubemaps.html [`bevy-baked-gi`]: https://github.com/pcwalton/bevy-baked-gi [glTF IBL Sampler]: https://github.com/KhronosGroup/glTF-IBL-Sampler |
||
![]() |
7b8305e5b4
|
Remove unnecessary parens (#11075)
# Objective - Increase readability. ## Solution - Remove unnecessary parens. |
||
![]() |
16c5a4b7cd
|
Fix BindingType import warning (#10818)
# Objective Fix this warning ``` warning: unused import: `BindingType` --> ...bevy/crates/bevy_pbr/src/render/mesh_view_bindings.rs:23:88 | 23 | BindGroup, BindGroupLayout, BindGroupLayoutEntry, BindGroupLayoutEntryBuilder, BindingType, | ^^^^^^^^^^^ | = note: `#[warn(unused_imports)]` on by default ``` ## Solution - Import via globstar Signed-off-by: Torstein Grindvik <torstein.grindvik@muybridge.com> Co-authored-by: Torstein Grindvik <torstein.grindvik@muybridge.com> |
||
![]() |
0f5d8128c9
|
Fix prepass binding issues causing crashes when not all prepass bindings are used (#10788)
# Objective Fixes https://github.com/bevyengine/bevy/issues/10786 ## Solution The bind_group_layout entries for the prepass were wrong when not all 4 prepass textures were used, as it just zipped [17, 18, 19, 20] with the smallvec of prepass `bind_group_layout` entries that potentially didn't contain 4 entries. (eg. if you had a depth and motion vector prepass but no normal prepass, then depth would be correct but the entry for the motion vector prepass would be 18 (normal prepass' spot) instead of 19). Change the prepass `get_bind_group_layout_entries` function to return an array of `[Option<BindGroupLayoutEntryBuilder>; 4]` and only add the layout entry if it exists. |
||
![]() |
6d0c11a28f
|
Bind group layout entries (#10224)
# Objective
- Follow up to #9694
## Solution
- Same api as #9694 but adapted for `BindGroupLayoutEntry`
- Use the same `ShaderStages` visibilty for all entries by default
- Add `BindingType` helper function that mirror the wgsl equivalent and
that make writing layouts much simpler.
Before:
```rust
let layout = render_device.create_bind_group_layout(&BindGroupLayoutDescriptor {
label: Some("post_process_bind_group_layout"),
entries: &[
BindGroupLayoutEntry {
binding: 0,
visibility: ShaderStages::FRAGMENT,
ty: BindingType::Texture {
sample_type: TextureSampleType::Float { filterable: true },
view_dimension: TextureViewDimension::D2,
multisampled: false,
},
count: None,
},
BindGroupLayoutEntry {
binding: 1,
visibility: ShaderStages::FRAGMENT,
ty: BindingType::Sampler(SamplerBindingType::Filtering),
count: None,
},
BindGroupLayoutEntry {
binding: 2,
visibility: ShaderStages::FRAGMENT,
ty: BindingType::Buffer {
ty: bevy::render::render_resource::BufferBindingType::Uniform,
has_dynamic_offset: false,
min_binding_size: Some(PostProcessSettings::min_size()),
},
count: None,
},
],
});
```
After:
```rust
let layout = render_device.create_bind_group_layout(
"post_process_bind_group_layout"),
&BindGroupLayoutEntries::sequential(
ShaderStages::FRAGMENT,
(
texture_2d_f32(),
sampler(SamplerBindingType::Filtering),
uniform_buffer(false, Some(PostProcessSettings::min_size())),
),
),
);
```
Here's a more extreme example in bevy_solari:
|
||
![]() |
44928e0df4
|
StandardMaterial Light Transmission (#8015)
# Objective
<img width="1920" alt="Screenshot 2023-04-26 at 01 07 34"
src="https://user-images.githubusercontent.com/418473/234467578-0f34187b-5863-4ea1-88e9-7a6bb8ce8da3.png">
This PR adds both diffuse and specular light transmission capabilities
to the `StandardMaterial`, with support for screen space refractions.
This enables realistically representing a wide range of real-world
materials, such as:
- Glass; (Including frosted glass)
- Transparent and translucent plastics;
- Various liquids and gels;
- Gemstones;
- Marble;
- Wax;
- Paper;
- Leaves;
- Porcelain.
Unlike existing support for transparency, light transmission does not
rely on fixed function alpha blending, and therefore works with both
`AlphaMode::Opaque` and `AlphaMode::Mask` materials.
## Solution
- Introduces a number of transmission related fields in the
`StandardMaterial`;
- For specular transmission:
- Adds logic to take a view main texture snapshot after the opaque
phase; (in order to perform screen space refractions)
- Introduces a new `Transmissive3d` phase to the renderer, to which all
meshes with `transmission > 0.0` materials are sent.
- Calculates a light exit point (of the approximate mesh volume) using
`ior` and `thickness` properties
- Samples the snapshot texture with an adaptive number of taps across a
`roughness`-controlled radius enabling “blurry” refractions
- For diffuse transmission:
- Approximates transmitted diffuse light by using a second, flipped +
displaced, diffuse-only Lambertian lobe for each light source.
## To Do
- [x] Figure out where `fresnel_mix()` is taking place, if at all, and
where `dielectric_specular` is being calculated, if at all, and update
them to use the `ior` value (Not a blocker, just a nice-to-have for more
correct BSDF)
- To the _best of my knowledge, this is now taking place, after
|
||
![]() |
6f2a5cb862
|
Bind group entries (#9694)
# Objective Simplify bind group creation code. alternative to (and based on) #9476 ## Solution - Add a `BindGroupEntries` struct that can transparently be used where `&[BindGroupEntry<'b>]` is required in BindGroupDescriptors. Allows constructing the descriptor's entries as: ```rust render_device.create_bind_group( "my_bind_group", &my_layout, &BindGroupEntries::with_indexes(( (2, &my_sampler), (3, my_uniform), )), ); ``` instead of ```rust render_device.create_bind_group( "my_bind_group", &my_layout, &[ BindGroupEntry { binding: 2, resource: BindingResource::Sampler(&my_sampler), }, BindGroupEntry { binding: 3, resource: my_uniform, }, ], ); ``` or ```rust render_device.create_bind_group( "my_bind_group", &my_layout, &BindGroupEntries::sequential((&my_sampler, my_uniform)), ); ``` instead of ```rust render_device.create_bind_group( "my_bind_group", &my_layout, &[ BindGroupEntry { binding: 0, resource: BindingResource::Sampler(&my_sampler), }, BindGroupEntry { binding: 1, resource: my_uniform, }, ], ); ``` the structs has no user facing macros, is tuple-type-based so stack allocated, and has no noticeable impact on compile time. - Also adds a `DynamicBindGroupEntries` struct with a similar api that uses a `Vec` under the hood and allows extending the entries. - Modifies `RenderDevice::create_bind_group` to take separate arguments `label`, `layout` and `entries` instead of a `BindGroupDescriptor` struct. The struct can't be stored due to the internal references, and with only 3 members arguably does not add enough context to justify itself. - Modify the codebase to use the new api and the `BindGroupEntries` / `DynamicBindGroupEntries` structs where appropriate (whenever the entries slice contains more than 1 member). ## Migration Guide - Calls to `RenderDevice::create_bind_group({BindGroupDescriptor { label, layout, entries })` must be amended to `RenderDevice::create_bind_group(label, layout, entries)`. - If `label`s have been specified as `"bind_group_name".into()`, they need to change to just `"bind_group_name"`. `Some("bind_group_name")` and `None` will still work, but `Some("bind_group_name")` can optionally be simplified to just `"bind_group_name"`. --------- Co-authored-by: IceSentry <IceSentry@users.noreply.github.com> |
||
![]() |
9b80205acb
|
Variable MeshPipeline View Bind Group Layout (#10156)
# Objective This PR aims to make it so that we don't accidentally go over `MAX_TEXTURE_IMAGE_UNITS` (in WebGL) or `maxSampledTexturesPerShaderStage` (in WebGPU), giving us some extra leeway to add more view bind group textures. (This PR is extracted from—and unblocks—#8015) ## Solution - We replace the existing `view_layout` and `view_layout_multisampled` pair with an array of 32 bind group layouts, generated ahead of time; - For now, these layouts cover all the possible combinations of: `multisampled`, `depth_prepass`, `normal_prepass`, `motion_vector_prepass` and `deferred_prepass`: - In the future, as @JMS55 pointed out, we can likely take out `motion_vector_prepass` and `deferred_prepass`, as these are not really needed for the mesh pipeline and can use separate pipelines. This would bring the possible combinations down to 8; - We can also add more "optional" textures as they become needed, allowing the engine to scale to a wider variety of use cases in lower end/web environments (e.g. some apps might just want normal and depth prepasses, others might only want light probes), while still keeping a high ceiling for high end native environments where more textures are supported. - While preallocating bind group layouts is relatively cheap, the number of combinations grows exponentially, so we should likely limit ourselves to something like at most 256–1024 total layouts until we find a better solution (like generating them lazily) - To make this mechanism a little bit more explicit/discoverable, so that compatibility with WebGPU/WebGL is not broken by accident, we add a `MESH_PIPELINE_VIEW_LAYOUT_SAFE_MAX_TEXTURES` const and warn whenever the number of textures in the layout crosses it. - The warning is gated by `#[cfg(debug_assertions)]` and not issued in release builds; - We're counting the actual textures in the bind group layout instead of using some roundabout metric so it should be accurate; - Right now `MESH_PIPELINE_VIEW_LAYOUT_SAFE_MAX_TEXTURES` is set to 10 in order to leave 6 textures free for other groups; - Currently there's no combination that would cause us to go over the limit, but that will change once #8015 lands. --- ## Changelog - `MeshPipeline` view bind group layouts now vary based on the current multisampling and prepass states, saving a couple of texture binding entries when prepasses are not in use. ## Migration Guide - `MeshPipeline::view_layout` and `MeshPipeline::view_layout_multisampled` have been replaced with a private array to accomodate for variable view bind group layouts. To obtain a view bind group layout for the current pipeline state, use the new `MeshPipeline::get_view_layout()` or `MeshPipeline::get_view_layout_from_key()` methods. |