bevy/crates/bevy_pbr/src/render/mesh_view_bindings.wgsl

100 lines
3.9 KiB
WebGPU Shading Language
Raw Normal View History

2022-05-31 23:23:25 +00:00
#define_import_path bevy_pbr::mesh_view_bindings
improve shader import model (#5703) # Objective operate on naga IR directly to improve handling of shader modules. - give codespan reporting into imported modules - allow glsl to be used from wgsl and vice-versa the ultimate objective is to make it possible to - provide user hooks for core shader functions (to modify light behaviour within the standard pbr pipeline, for example) - make automatic binding slot allocation possible but ... since this is already big, adds some value and (i think) is at feature parity with the existing code, i wanted to push this now. ## Solution i made a crate called naga_oil (https://github.com/robtfm/naga_oil - unpublished for now, could be part of bevy) which manages modules by - building each module independantly to naga IR - creating "header" files for each supported language, which are used to build dependent modules/shaders - make final shaders by combining the shader IR with the IR for imported modules then integrated this into bevy, replacing some of the existing shader processing stuff. also reworked examples to reflect this. ## Migration Guide shaders that don't use `#import` directives should work without changes. the most notable user-facing difference is that imported functions/variables/etc need to be qualified at point of use, and there's no "leakage" of visible stuff into your shader scope from the imports of your imports, so if you used things imported by your imports, you now need to import them directly and qualify them. the current strategy of including/'spreading' `mesh_vertex_output` directly into a struct doesn't work any more, so these need to be modified as per the examples (e.g. color_material.wgsl, or many others). mesh data is assumed to be in bindgroup 2 by default, if mesh data is bound into bindgroup 1 instead then the shader def `MESH_BINDGROUP_1` needs to be added to the pipeline shader_defs.
2023-06-27 00:29:22 +00:00
#import bevy_pbr::mesh_view_types as types
update shader imports (#10180) # Objective - bump naga_oil to 0.10 - update shader imports to use rusty syntax ## Migration Guide naga_oil 0.10 reworks the import mechanism to support more syntax to make it more rusty, and test for item use before importing to determine which imports are modules and which are items, which allows: - use rust-style imports ``` #import bevy_pbr::{ pbr_functions::{alpha_discard as discard, apply_pbr_lighting}, mesh_bindings, } ``` - import partial paths: ``` #import part::of::path ... path::remainder::function(); ``` which will call to `part::of::path::remainder::function` - use fully qualified paths without importing: ``` // #import bevy_pbr::pbr_functions bevy_pbr::pbr_functions::pbr() ``` - use imported items without qualifying ``` #import bevy_pbr::pbr_functions::pbr // for backwards compatibility the old style is still supported: // #import bevy_pbr::pbr_functions pbr ... pbr() ``` - allows most imported items to end with `_` and numbers (naga_oil#30). still doesn't allow struct members to end with `_` or numbers but it's progress. - the vast majority of existing shader code will work without changes, but will emit "deprecated" warnings for old-style imports. these can be suppressed with the `allow-deprecated` feature. - partly breaks overrides (as far as i'm aware nobody uses these yet) - now overrides will only be applied if the overriding module is added as an additional import in the arguments to `Composer::make_naga_module` or `Composer::add_composable_module`. this is necessary to support determining whether imports are modules or items.
2023-10-21 11:51:58 +00:00
#import bevy_render::{
view::View,
globals::Globals,
}
2022-05-31 23:23:25 +00:00
@group(0) @binding(0) var<uniform> view: View;
@group(0) @binding(1) var<uniform> lights: types::Lights;
#ifdef NO_CUBE_ARRAY_TEXTURES_SUPPORT
@group(0) @binding(2) var point_shadow_textures: texture_depth_cube;
2022-05-31 23:23:25 +00:00
#else
@group(0) @binding(2) var point_shadow_textures: texture_depth_cube_array;
2022-05-31 23:23:25 +00:00
#endif
@group(0) @binding(3) var point_shadow_textures_sampler: sampler_comparison;
2022-05-31 23:23:25 +00:00
#ifdef NO_ARRAY_TEXTURES_SUPPORT
@group(0) @binding(4) var directional_shadow_textures: texture_depth_2d;
2022-05-31 23:23:25 +00:00
#else
@group(0) @binding(4) var directional_shadow_textures: texture_depth_2d_array;
2022-05-31 23:23:25 +00:00
#endif
@group(0) @binding(5) var directional_shadow_textures_sampler: sampler_comparison;
2022-05-31 23:23:25 +00:00
#if AVAILABLE_STORAGE_BUFFER_BINDINGS >= 3
@group(0) @binding(6) var<storage> point_lights: types::PointLights;
@group(0) @binding(7) var<storage> cluster_light_index_lists: types::ClusterLightIndexLists;
@group(0) @binding(8) var<storage> cluster_offsets_and_counts: types::ClusterOffsetsAndCounts;
2022-05-31 23:23:25 +00:00
#else
@group(0) @binding(6) var<uniform> point_lights: types::PointLights;
@group(0) @binding(7) var<uniform> cluster_light_index_lists: types::ClusterLightIndexLists;
@group(0) @binding(8) var<uniform> cluster_offsets_and_counts: types::ClusterOffsetsAndCounts;
2022-05-31 23:23:25 +00:00
#endif
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
@group(0) @binding(9) var<uniform> globals: Globals;
@group(0) @binding(10) var<uniform> fog: types::Fog;
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
2024-01-19 07:33:52 +00:00
@group(0) @binding(11) var<uniform> light_probes: types::LightProbes;
Add depth and normal prepass (#6284) # Objective - Add a configurable prepass - A depth prepass is useful for various shader effects and to reduce overdraw. It can be expansive depending on the scene so it's important to be able to disable it if you don't need any effects that uses it or don't suffer from excessive overdraw. - The goal is to eventually use it for things like TAA, Ambient Occlusion, SSR and various other techniques that can benefit from having a prepass. ## Solution The prepass node is inserted before the main pass. It runs for each `Camera3d` with a prepass component (`DepthPrepass`, `NormalPrepass`). The presence of one of those components is used to determine which textures are generated in the prepass. When any prepass is enabled, the depth buffer generated will be used by the main pass to reduce overdraw. The prepass runs for each `Material` created with the `MaterialPlugin::prepass_enabled` option set to `true`. You can overload the shader used by the prepass by using `Material::prepass_vertex_shader()` and/or `Material::prepass_fragment_shader()`. It will also use the `Material::specialize()` for more advanced use cases. It is enabled by default on all materials. The prepass works on opaque materials and materials using an alpha mask. Transparent materials are ignored. The `StandardMaterial` overloads the prepass fragment shader to support alpha mask and normal maps. --- ## Changelog - Add a new `PrepassNode` that runs before the main pass - Add a `PrepassPlugin` to extract/prepare/queue the necessary data - Add a `DepthPrepass` and `NormalPrepass` component to control which textures will be created by the prepass and available in later passes. - Add a new `prepass_enabled` flag to the `MaterialPlugin` that will control if a material uses the prepass or not. - Add a new `prepass_enabled` flag to the `PbrPlugin` to control if the StandardMaterial uses the prepass. Currently defaults to false. - Add `Material::prepass_vertex_shader()` and `Material::prepass_fragment_shader()` to control the prepass from the `Material` ## Notes In bevy's sample 3d scene, the performance is actually worse when enabling the prepass, but on more complex scenes the performance is generally better. I would like more testing on this, but @DGriffin91 has reported a very noticeable improvements in some scenes. The prepass is also used by @JMS55 for TAA and GTAO discord thread: <https://discord.com/channels/691052431525675048/1011624228627419187> This PR was built on top of the work of multiple people Co-Authored-By: @superdump Co-Authored-By: @robtfm Co-Authored-By: @JMS55 Co-authored-by: Charles <IceSentry@users.noreply.github.com> Co-authored-by: JMS55 <47158642+JMS55@users.noreply.github.com>
2023-01-19 22:11:13 +00:00
const VISIBILITY_RANGE_UNIFORM_BUFFER_SIZE: u32 = 64u;
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: ![Screenshot 2024-04-09 185541](https://github.com/bevyengine/bevy/assets/157897/7e8be017-7187-4471-8866-974e2d8f2623) Low-poly model up close: ![Screenshot 2024-04-09 185546](https://github.com/bevyengine/bevy/assets/157897/429603fe-6bb7-4246-8b4e-b4888fd1d3a0) Crossfading between the two: ![Screenshot 2024-04-09 185604](https://github.com/bevyengine/bevy/assets/157897/86d0d543-f8f3-49ec-8fe5-caa4d0784fd4) --------- Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2024-05-03 00:11:35 +00:00
#if AVAILABLE_STORAGE_BUFFER_BINDINGS >= 6
@group(0) @binding(12) var<storage> visibility_ranges: array<vec4<f32>>;
#else
@group(0) @binding(12) var<uniform> visibility_ranges: array<vec4<f32>, VISIBILITY_RANGE_UNIFORM_BUFFER_SIZE>;
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: ![Screenshot 2024-04-09 185541](https://github.com/bevyengine/bevy/assets/157897/7e8be017-7187-4471-8866-974e2d8f2623) Low-poly model up close: ![Screenshot 2024-04-09 185546](https://github.com/bevyengine/bevy/assets/157897/429603fe-6bb7-4246-8b4e-b4888fd1d3a0) Crossfading between the two: ![Screenshot 2024-04-09 185604](https://github.com/bevyengine/bevy/assets/157897/86d0d543-f8f3-49ec-8fe5-caa4d0784fd4) --------- Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2024-05-03 00:11:35 +00:00
#endif
@group(0) @binding(13) var screen_space_ambient_occlusion_texture: texture_2d<f32>;
Screen Space Ambient Occlusion (SSAO) MVP (#7402) ![image](https://github.com/bevyengine/bevy/assets/47158642/dbb62645-f639-4f2b-b84b-26fd915c186d) # Objective - Add Screen space ambient occlusion (SSAO). SSAO approximates small-scale, local occlusion of _indirect_ diffuse light between objects. SSAO does not apply to direct lighting, such as point or directional lights. - This darkens creases, e.g. on staircases, and gives nice contact shadows where objects meet, giving entities a more "grounded" feel. - Closes https://github.com/bevyengine/bevy/issues/3632. ## Solution - Implement the GTAO algorithm. - https://www.activision.com/cdn/research/Practical_Real_Time_Strategies_for_Accurate_Indirect_Occlusion_NEW%20VERSION_COLOR.pdf - https://blog.selfshadow.com/publications/s2016-shading-course/activision/s2016_pbs_activision_occlusion.pdf - Source code heavily based on [Intel's XeGTAO](https://github.com/GameTechDev/XeGTAO/blob/0d177ce06bfa642f64d8af4de1197ad1bcb862d4/Source/Rendering/Shaders/XeGTAO.hlsli). - Add an SSAO bevy example. ## Algorithm Overview * Run a depth and normal prepass * Create downscaled mips of the depth texture (preprocess_depths pass) * GTAO pass - for each pixel, take several random samples from the depth+normal buffers, reconstruct world position, raytrace in screen space to estimate occlusion. Rather then doing completely random samples on a hemisphere, you choose random _slices_ of the hemisphere, and then can analytically compute the full occlusion of that slice. Also compute edges based on depth differences here. * Spatial denoise pass - bilateral blur, using edge detection to not blur over edges. This is the final SSAO result. * Main pass - if SSAO exists, sample the SSAO texture, and set occlusion to be the minimum of ssao/material occlusion. This then feeds into the rest of the PBR shader as normal. --- ## Future Improvements - Maybe remove the low quality preset for now (too noisy) - WebGPU fallback (see below) - Faster depth->world position (see reverted code) - Bent normals - Try interleaved gradient noise or spatiotemporal blue noise - Replace the spatial denoiser with a combined spatial+temporal denoiser - Render at half resolution and use a bilateral upsample - Better multibounce approximation (https://drive.google.com/file/d/1SyagcEVplIm2KkRD3WQYSO9O0Iyi1hfy/view) ## Far-Future Performance Improvements - F16 math (missing naga-wgsl support https://github.com/gfx-rs/naga/issues/1884) - Faster coordinate space conversion for normals - Faster depth mipchain creation (https://github.com/GPUOpen-Effects/FidelityFX-SPD) (wgpu/naga does not currently support subgroup ops) - Deinterleaved SSAO for better cache efficiency (https://developer.nvidia.com/sites/default/files/akamai/gameworks/samples/DeinterleavedTexturing.pdf) ## Other Interesting Papers - Visibility bitmask (https://link.springer.com/article/10.1007/s00371-022-02703-y, https://cdrinmatane.github.io/posts/cgspotlight-slides/) - Screen space diffuse lighting (https://github.com/Patapom/GodComplex/blob/master/Tests/TestHBIL/2018%20Mayaux%20-%20Horizon-Based%20Indirect%20Lighting%20(HBIL).pdf) ## Platform Support * SSAO currently does not work on DirectX12 due to issues with wgpu and naga: * https://github.com/gfx-rs/wgpu/pull/3798 * https://github.com/gfx-rs/naga/pull/2353 * SSAO currently does not work on WebGPU because r16float is not a valid storage texture format https://gpuweb.github.io/gpuweb/wgsl/#storage-texel-formats. We can fix this with a fallback to r32float. --- ## Changelog - Added ScreenSpaceAmbientOcclusionSettings, ScreenSpaceAmbientOcclusionQualityLevel, and ScreenSpaceAmbientOcclusionBundle --------- Co-authored-by: IceSentry <c.giguere42@gmail.com> Co-authored-by: IceSentry <IceSentry@users.noreply.github.com> Co-authored-by: Daniel Chia <danstryder@gmail.com> Co-authored-by: Elabajaba <Elabajaba@users.noreply.github.com> Co-authored-by: Robert Swain <robert.swain@gmail.com> Co-authored-by: robtfm <50659922+robtfm@users.noreply.github.com> Co-authored-by: Brandon Dyer <brandondyer64@gmail.com> Co-authored-by: Edgar Geier <geieredgar@gmail.com> Co-authored-by: Nicola Papale <nicopap@users.noreply.github.com> Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2023-06-18 21:05:55 +00:00
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
2024-01-19 07:33:52 +00:00
#ifdef MULTIPLE_LIGHT_PROBES_IN_ARRAY
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: ![Screenshot 2024-04-09 185541](https://github.com/bevyengine/bevy/assets/157897/7e8be017-7187-4471-8866-974e2d8f2623) Low-poly model up close: ![Screenshot 2024-04-09 185546](https://github.com/bevyengine/bevy/assets/157897/429603fe-6bb7-4246-8b4e-b4888fd1d3a0) Crossfading between the two: ![Screenshot 2024-04-09 185604](https://github.com/bevyengine/bevy/assets/157897/86d0d543-f8f3-49ec-8fe5-caa4d0784fd4) --------- Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2024-05-03 00:11:35 +00:00
@group(0) @binding(14) var diffuse_environment_maps: binding_array<texture_cube<f32>, 8u>;
@group(0) @binding(15) var specular_environment_maps: binding_array<texture_cube<f32>, 8u>;
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
2024-01-19 07:33:52 +00:00
#else
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: ![Screenshot 2024-04-09 185541](https://github.com/bevyengine/bevy/assets/157897/7e8be017-7187-4471-8866-974e2d8f2623) Low-poly model up close: ![Screenshot 2024-04-09 185546](https://github.com/bevyengine/bevy/assets/157897/429603fe-6bb7-4246-8b4e-b4888fd1d3a0) Crossfading between the two: ![Screenshot 2024-04-09 185604](https://github.com/bevyengine/bevy/assets/157897/86d0d543-f8f3-49ec-8fe5-caa4d0784fd4) --------- Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2024-05-03 00:11:35 +00:00
@group(0) @binding(14) var diffuse_environment_map: texture_cube<f32>;
@group(0) @binding(15) var specular_environment_map: texture_cube<f32>;
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
2024-01-19 07:33:52 +00:00
#endif
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: ![Screenshot 2024-04-09 185541](https://github.com/bevyengine/bevy/assets/157897/7e8be017-7187-4471-8866-974e2d8f2623) Low-poly model up close: ![Screenshot 2024-04-09 185546](https://github.com/bevyengine/bevy/assets/157897/429603fe-6bb7-4246-8b4e-b4888fd1d3a0) Crossfading between the two: ![Screenshot 2024-04-09 185604](https://github.com/bevyengine/bevy/assets/157897/86d0d543-f8f3-49ec-8fe5-caa4d0784fd4) --------- Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2024-05-03 00:11:35 +00:00
@group(0) @binding(16) var environment_map_sampler: sampler;
EnvironmentMapLight, BRDF Improvements (#7051) (Before) ![image](https://user-images.githubusercontent.com/47158642/213946111-15ec758f-1f1d-443c-b196-1fdcd4ae49da.png) (After) ![image](https://user-images.githubusercontent.com/47158642/217051179-67381e73-dd44-461b-a2c7-87b0440ef8de.png) ![image](https://user-images.githubusercontent.com/47158642/212492404-524e4ad3-7837-4ed4-8b20-2abc276aa8e8.png) # Objective - Improve lighting; especially reflections. - Closes https://github.com/bevyengine/bevy/issues/4581. ## Solution - Implement environment maps, providing better ambient light. - Add microfacet multibounce approximation for specular highlights from Filament. - Occlusion is no longer incorrectly applied to direct lighting. It now only applies to diffuse indirect light. Unsure if it's also supposed to apply to specular indirect light - the glTF specification just says "indirect light". In the case of ambient occlusion, for instance, that's usually only calculated as diffuse though. For now, I'm choosing to apply this just to indirect diffuse light, and not specular. - Modified the PBR example to use an environment map, and have labels. - Added `FallbackImageCubemap`. ## Implementation - IBL technique references can be found in environment_map.wgsl. - It's more accurate to use a LUT for the scale/bias. Filament has a good reference on generating this LUT. For now, I just used an analytic approximation. - For now, environment maps must first be prefiltered outside of bevy using a 3rd party tool. See the `EnvironmentMap` documentation. - Eventually, we should have our own prefiltering code, so that we can have dynamically changing environment maps, as well as let users drop in an HDR image and use asset preprocessing to create the needed textures using only bevy. --- ## Changelog - Added an `EnvironmentMapLight` camera component that adds additional ambient light to a scene. - StandardMaterials will now appear brighter and more saturated at high roughness, due to internal material changes. This is more physically correct. - Fixed StandardMaterial occlusion being incorrectly applied to direct lighting. - Added `FallbackImageCubemap`. Co-authored-by: IceSentry <c.giguere42@gmail.com> Co-authored-by: James Liu <contact@jamessliu.com> Co-authored-by: Rob Parrett <robparrett@gmail.com>
2023-02-09 16:46:32 +00:00
#ifdef IRRADIANCE_VOLUMES_ARE_USABLE
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.
2024-02-06 23:23:20 +00:00
#ifdef MULTIPLE_LIGHT_PROBES_IN_ARRAY
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: ![Screenshot 2024-04-09 185541](https://github.com/bevyengine/bevy/assets/157897/7e8be017-7187-4471-8866-974e2d8f2623) Low-poly model up close: ![Screenshot 2024-04-09 185546](https://github.com/bevyengine/bevy/assets/157897/429603fe-6bb7-4246-8b4e-b4888fd1d3a0) Crossfading between the two: ![Screenshot 2024-04-09 185604](https://github.com/bevyengine/bevy/assets/157897/86d0d543-f8f3-49ec-8fe5-caa4d0784fd4) --------- Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2024-05-03 00:11:35 +00:00
@group(0) @binding(17) var irradiance_volumes: binding_array<texture_3d<f32>, 8u>;
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.
2024-02-06 23:23:20 +00:00
#else
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: ![Screenshot 2024-04-09 185541](https://github.com/bevyengine/bevy/assets/157897/7e8be017-7187-4471-8866-974e2d8f2623) Low-poly model up close: ![Screenshot 2024-04-09 185546](https://github.com/bevyengine/bevy/assets/157897/429603fe-6bb7-4246-8b4e-b4888fd1d3a0) Crossfading between the two: ![Screenshot 2024-04-09 185604](https://github.com/bevyengine/bevy/assets/157897/86d0d543-f8f3-49ec-8fe5-caa4d0784fd4) --------- Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2024-05-03 00:11:35 +00:00
@group(0) @binding(17) var irradiance_volume: texture_3d<f32>;
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.
2024-02-06 23:23:20 +00:00
#endif
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: ![Screenshot 2024-04-09 185541](https://github.com/bevyengine/bevy/assets/157897/7e8be017-7187-4471-8866-974e2d8f2623) Low-poly model up close: ![Screenshot 2024-04-09 185546](https://github.com/bevyengine/bevy/assets/157897/429603fe-6bb7-4246-8b4e-b4888fd1d3a0) Crossfading between the two: ![Screenshot 2024-04-09 185604](https://github.com/bevyengine/bevy/assets/157897/86d0d543-f8f3-49ec-8fe5-caa4d0784fd4) --------- Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2024-05-03 00:11:35 +00:00
@group(0) @binding(18) var irradiance_volume_sampler: sampler;
#endif
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.
2024-02-06 23:23:20 +00:00
// NB: If you change these, make sure to update `tonemapping_shared.wgsl` too.
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: ![Screenshot 2024-04-09 185541](https://github.com/bevyengine/bevy/assets/157897/7e8be017-7187-4471-8866-974e2d8f2623) Low-poly model up close: ![Screenshot 2024-04-09 185546](https://github.com/bevyengine/bevy/assets/157897/429603fe-6bb7-4246-8b4e-b4888fd1d3a0) Crossfading between the two: ![Screenshot 2024-04-09 185604](https://github.com/bevyengine/bevy/assets/157897/86d0d543-f8f3-49ec-8fe5-caa4d0784fd4) --------- Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2024-05-03 00:11:35 +00:00
@group(0) @binding(19) var dt_lut_texture: texture_3d<f32>;
@group(0) @binding(20) var dt_lut_sampler: sampler;
#ifdef MULTISAMPLED
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.
2023-10-21 11:19:44 +00:00
#ifdef DEPTH_PREPASS
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: ![Screenshot 2024-04-09 185541](https://github.com/bevyengine/bevy/assets/157897/7e8be017-7187-4471-8866-974e2d8f2623) Low-poly model up close: ![Screenshot 2024-04-09 185546](https://github.com/bevyengine/bevy/assets/157897/429603fe-6bb7-4246-8b4e-b4888fd1d3a0) Crossfading between the two: ![Screenshot 2024-04-09 185604](https://github.com/bevyengine/bevy/assets/157897/86d0d543-f8f3-49ec-8fe5-caa4d0784fd4) --------- Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2024-05-03 00:11:35 +00:00
@group(0) @binding(21) var depth_prepass_texture: texture_depth_multisampled_2d;
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.
2023-10-21 11:19:44 +00:00
#endif // DEPTH_PREPASS
#ifdef NORMAL_PREPASS
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: ![Screenshot 2024-04-09 185541](https://github.com/bevyengine/bevy/assets/157897/7e8be017-7187-4471-8866-974e2d8f2623) Low-poly model up close: ![Screenshot 2024-04-09 185546](https://github.com/bevyengine/bevy/assets/157897/429603fe-6bb7-4246-8b4e-b4888fd1d3a0) Crossfading between the two: ![Screenshot 2024-04-09 185604](https://github.com/bevyengine/bevy/assets/157897/86d0d543-f8f3-49ec-8fe5-caa4d0784fd4) --------- Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2024-05-03 00:11:35 +00:00
@group(0) @binding(22) var normal_prepass_texture: texture_multisampled_2d<f32>;
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.
2023-10-21 11:19:44 +00:00
#endif // NORMAL_PREPASS
#ifdef MOTION_VECTOR_PREPASS
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: ![Screenshot 2024-04-09 185541](https://github.com/bevyengine/bevy/assets/157897/7e8be017-7187-4471-8866-974e2d8f2623) Low-poly model up close: ![Screenshot 2024-04-09 185546](https://github.com/bevyengine/bevy/assets/157897/429603fe-6bb7-4246-8b4e-b4888fd1d3a0) Crossfading between the two: ![Screenshot 2024-04-09 185604](https://github.com/bevyengine/bevy/assets/157897/86d0d543-f8f3-49ec-8fe5-caa4d0784fd4) --------- Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2024-05-03 00:11:35 +00:00
@group(0) @binding(23) var motion_vector_prepass_texture: texture_multisampled_2d<f32>;
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.
2023-10-21 11:19:44 +00:00
#endif // MOTION_VECTOR_PREPASS
#else // MULTISAMPLED
#ifdef DEPTH_PREPASS
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: ![Screenshot 2024-04-09 185541](https://github.com/bevyengine/bevy/assets/157897/7e8be017-7187-4471-8866-974e2d8f2623) Low-poly model up close: ![Screenshot 2024-04-09 185546](https://github.com/bevyengine/bevy/assets/157897/429603fe-6bb7-4246-8b4e-b4888fd1d3a0) Crossfading between the two: ![Screenshot 2024-04-09 185604](https://github.com/bevyengine/bevy/assets/157897/86d0d543-f8f3-49ec-8fe5-caa4d0784fd4) --------- Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2024-05-03 00:11:35 +00:00
@group(0) @binding(21) var depth_prepass_texture: texture_depth_2d;
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.
2023-10-21 11:19:44 +00:00
#endif // DEPTH_PREPASS
#ifdef NORMAL_PREPASS
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: ![Screenshot 2024-04-09 185541](https://github.com/bevyengine/bevy/assets/157897/7e8be017-7187-4471-8866-974e2d8f2623) Low-poly model up close: ![Screenshot 2024-04-09 185546](https://github.com/bevyengine/bevy/assets/157897/429603fe-6bb7-4246-8b4e-b4888fd1d3a0) Crossfading between the two: ![Screenshot 2024-04-09 185604](https://github.com/bevyengine/bevy/assets/157897/86d0d543-f8f3-49ec-8fe5-caa4d0784fd4) --------- Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2024-05-03 00:11:35 +00:00
@group(0) @binding(22) var normal_prepass_texture: texture_2d<f32>;
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.
2023-10-21 11:19:44 +00:00
#endif // NORMAL_PREPASS
#ifdef MOTION_VECTOR_PREPASS
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: ![Screenshot 2024-04-09 185541](https://github.com/bevyengine/bevy/assets/157897/7e8be017-7187-4471-8866-974e2d8f2623) Low-poly model up close: ![Screenshot 2024-04-09 185546](https://github.com/bevyengine/bevy/assets/157897/429603fe-6bb7-4246-8b4e-b4888fd1d3a0) Crossfading between the two: ![Screenshot 2024-04-09 185604](https://github.com/bevyengine/bevy/assets/157897/86d0d543-f8f3-49ec-8fe5-caa4d0784fd4) --------- Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2024-05-03 00:11:35 +00:00
@group(0) @binding(23) var motion_vector_prepass_texture: texture_2d<f32>;
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.
2023-10-21 11:19:44 +00:00
#endif // MOTION_VECTOR_PREPASS
#endif // MULTISAMPLED
#ifdef DEFERRED_PREPASS
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: ![Screenshot 2024-04-09 185541](https://github.com/bevyengine/bevy/assets/157897/7e8be017-7187-4471-8866-974e2d8f2623) Low-poly model up close: ![Screenshot 2024-04-09 185546](https://github.com/bevyengine/bevy/assets/157897/429603fe-6bb7-4246-8b4e-b4888fd1d3a0) Crossfading between the two: ![Screenshot 2024-04-09 185604](https://github.com/bevyengine/bevy/assets/157897/86d0d543-f8f3-49ec-8fe5-caa4d0784fd4) --------- Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2024-05-03 00:11:35 +00:00
@group(0) @binding(24) var deferred_prepass_texture: texture_2d<u32>;
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.
2023-10-21 11:19:44 +00:00
#endif // DEFERRED_PREPASS
`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 964340cdd. The fresnel mix is actually "split" into two parts in our implementation, one `(1 - fresnel(...))` in the transmission, and `fresnel()` in the light implementations. A surface with more reflectance now will produce slightly dimmer transmission towards the grazing angle, as more of the light gets reflected. - [x] Add `transmission_texture` - [x] Add `diffuse_transmission_texture` - [x] Add `thickness_texture` - [x] Add `attenuation_distance` and `attenuation_color` - [x] Connect values to glTF loader - [x] `transmission` and `transmission_texture` - [x] `thickness` and `thickness_texture` - [x] `ior` - [ ] `diffuse_transmission` and `diffuse_transmission_texture` (needs upstream support in `gltf` crate, not a blocker) - [x] Add support for multiple screen space refraction “steps” - [x] Conditionally create no transmission snapshot texture at all if `steps == 0` - [x] Conditionally enable/disable screen space refraction transmission snapshots - [x] Read from depth pre-pass to prevent refracting pixels in front of the light exit point - [x] Use `interleaved_gradient_noise()` function for sampling blur in a way that benefits from TAA - [x] Drill down a TAA `#define`, tweak some aspects of the effect conditionally based on it - [x] Remove const array that's crashing under HLSL (unless a new `naga` release with https://github.com/gfx-rs/naga/pull/2496 comes out before we merge this) - [ ] Look into alternatives to the `switch` hack for dynamically indexing the const array (might not be needed, compilers seem to be decent at expanding it) - [ ] Add pipeline keys for gating transmission (do we really want/need this?) - [x] Tweak some material field/function names? ## A Note on Texture Packing _This was originally added as a comment to the `specular_transmission_texture`, `thickness_texture` and `diffuse_transmission_texture` documentation, I removed it since it was more confusing than helpful, and will likely be made redundant/will need to be updated once we have a better infrastructure for preprocessing assets_ Due to how channels are mapped, you can more efficiently use a single shared texture image for configuring the following: - R - `specular_transmission_texture` - G - `thickness_texture` - B - _unused_ - A - `diffuse_transmission_texture` The `KHR_materials_diffuse_transmission` glTF extension also defines a `diffuseTransmissionColorTexture`, that _we don't currently support_. One might choose to pack the intensity and color textures together, using RGB for the color and A for the intensity, in which case this packing advice doesn't really apply. --- ## Changelog - Added a new `Transmissive3d` render phase for rendering specular transmissive materials with screen space refractions - Added rendering support for transmitted environment map light on the `StandardMaterial` as a fallback for screen space refractions - Added `diffuse_transmission`, `specular_transmission`, `thickness`, `ior`, `attenuation_distance` and `attenuation_color` to the `StandardMaterial` - Added `diffuse_transmission_texture`, `specular_transmission_texture`, `thickness_texture` to the `StandardMaterial`, gated behind a new `pbr_transmission_textures` cargo feature (off by default, for maximum hardware compatibility) - Added `Camera3d::screen_space_specular_transmission_steps` for controlling the number of “layers of transparency” rendered for transmissive objects - Added a `TransmittedShadowReceiver` component for enabling shadows in (diffusely) transmitted light. (disabled by default, as it requires carefully setting up the `thickness` to avoid self-shadow artifacts) - Added support for the `KHR_materials_transmission`, `KHR_materials_ior` and `KHR_materials_volume` glTF extensions - Renamed items related to temporal jitter for greater consistency ## Migration Guide - `SsaoPipelineKey::temporal_noise` has been renamed to `SsaoPipelineKey::temporal_jitter` - The `TAA` shader def (controlled by the presence of the `TemporalAntiAliasSettings` component in the camera) has been replaced with the `TEMPORAL_JITTER` shader def (controlled by the presence of the `TemporalJitter` component in the camera) - `MeshPipelineKey::TAA` has been replaced by `MeshPipelineKey::TEMPORAL_JITTER` - The `TEMPORAL_NOISE` shader def has been consolidated with `TEMPORAL_JITTER`
2023-10-31 20:59:02 +00:00
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: ![Screenshot 2024-04-09 185541](https://github.com/bevyengine/bevy/assets/157897/7e8be017-7187-4471-8866-974e2d8f2623) Low-poly model up close: ![Screenshot 2024-04-09 185546](https://github.com/bevyengine/bevy/assets/157897/429603fe-6bb7-4246-8b4e-b4888fd1d3a0) Crossfading between the two: ![Screenshot 2024-04-09 185604](https://github.com/bevyengine/bevy/assets/157897/86d0d543-f8f3-49ec-8fe5-caa4d0784fd4) --------- Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2024-05-03 00:11:35 +00:00
@group(0) @binding(25) var view_transmission_texture: texture_2d<f32>;
@group(0) @binding(26) var view_transmission_sampler: sampler;