From f835caa29e2f65b8e3bb41668193c25a496c433e Mon Sep 17 00:00:00 2001 From: Lucas Farias Date: Sun, 30 Mar 2025 23:05:29 -0300 Subject: [PATCH 1/4] Extract non-pbr logic from `bevy_pbr` --- Cargo.toml | 4 + crates/bevy_gizmos/Cargo.toml | 2 +- crates/bevy_gizmos/src/config.rs | 4 +- crates/bevy_gizmos/src/lib.rs | 34 +- crates/bevy_gizmos/src/light.rs | 2 +- crates/bevy_gizmos/src/pipeline_3d.rs | 4 +- crates/bevy_gizmos/src/retained.rs | 2 +- crates/bevy_gltf/Cargo.toml | 1 + crates/bevy_gltf/src/loader/mod.rs | 5 +- crates/bevy_internal/Cargo.toml | 4 +- crates/bevy_internal/src/default_plugins.rs | 2 + crates/bevy_internal/src/lib.rs | 2 + crates/bevy_internal/src/prelude.rs | 4 + crates/bevy_pbr/Cargo.toml | 1 + crates/bevy_pbr/src/lib.rs | 413 +------- crates/bevy_pbr/src/pbr_material.rs | 20 +- crates/bevy_pbr/src/wireframe.rs | 22 +- crates/bevy_render_3d/Cargo.toml | 82 ++ crates/bevy_render_3d/LICENSE-APACHE | 176 ++++ crates/bevy_render_3d/LICENSE-MIT | 19 + crates/bevy_render_3d/README.md | 7 + .../src/atmosphere/aerial_view_lut.wgsl | 0 .../src/atmosphere/bindings.wgsl | 0 .../src/atmosphere/bruneton_functions.wgsl | 0 .../src/atmosphere/functions.wgsl | 0 .../src/atmosphere/mod.rs | 0 .../src/atmosphere/multiscattering_lut.wgsl | 0 .../src/atmosphere/node.rs | 0 .../src/atmosphere/render_sky.wgsl | 0 .../src/atmosphere/resources.rs | 0 .../src/atmosphere/sky_view_lut.wgsl | 0 .../src/atmosphere/transmittance_lut.wgsl | 0 .../src/atmosphere/types.wgsl | 0 .../src/cluster/assign.rs | 0 .../src/cluster/mod.rs | 0 .../src/cluster/test.rs | 0 .../src/components.rs | 0 .../src/decal/clustered.rs | 0 .../src/decal/clustered.wgsl | 0 .../src/decal/forward.rs | 21 +- .../src/decal/forward_decal.wgsl | 0 .../src/decal/mod.rs | 0 .../src/deferred/deferred_lighting.wgsl | 0 .../src/deferred/mod.rs | 0 .../src/deferred/pbr_deferred_functions.wgsl | 0 .../src/deferred/pbr_deferred_types.wgsl | 0 .../src/extended_material.rs | 0 .../{bevy_pbr => bevy_render_3d}/src/fog.rs | 7 +- crates/bevy_render_3d/src/lib.rs | 422 +++++++++ .../src/light/ambient_light.rs | 4 +- .../src/light/directional_light.rs | 2 +- .../src/light/mod.rs | 12 +- .../src/light/point_light.rs | 0 .../src/light/spot_light.rs | 0 .../src/light_probe/environment_map.rs | 0 .../src/light_probe/environment_map.wgsl | 0 .../src/light_probe/irradiance_volume.rs | 0 .../src/light_probe/irradiance_volume.wgsl | 0 .../src/light_probe/light_probe.wgsl | 0 .../src/light_probe/mod.rs | 0 .../src/lightmap/lightmap.wgsl | 0 .../src/lightmap/mod.rs | 10 +- .../src/material.rs | 2 +- .../src/material_bind_groups.rs | 0 .../src/mesh_material.rs | 14 +- .../src/meshlet/asset.rs | 0 .../src/meshlet/clear_visibility_buffer.wgsl | 0 .../src/meshlet/cull_clusters.wgsl | 0 .../dummy_visibility_buffer_resolve.wgsl | 0 .../src/meshlet/fill_cluster_buffers.wgsl | 0 .../src/meshlet/from_mesh.rs | 0 .../src/meshlet/instance_manager.rs | 0 .../src/meshlet/material_pipeline_prepare.rs | 0 .../src/meshlet/material_shade_nodes.rs | 0 .../src/meshlet/meshlet_bindings.wgsl | 0 .../src/meshlet/meshlet_mesh_manager.rs | 0 .../src/meshlet/meshlet_mesh_material.wgsl | 0 .../src/meshlet/meshlet_preview.png | Bin .../src/meshlet/mod.rs | 0 .../src/meshlet/persistent_buffer.rs | 0 .../src/meshlet/persistent_buffer_impls.rs | 0 .../src/meshlet/pipelines.rs | 0 .../src/meshlet/remap_1d_to_2d_dispatch.wgsl | 0 .../src/meshlet/resolve_render_targets.wgsl | 0 .../src/meshlet/resource_manager.rs | 0 .../visibility_buffer_hardware_raster.wgsl | 0 .../meshlet/visibility_buffer_raster_node.rs | 0 .../meshlet/visibility_buffer_resolve.wgsl | 0 .../visibility_buffer_software_raster.wgsl | 0 .../src/prepass/mod.rs | 28 +- .../src/prepass/prepass.wgsl | 0 .../src/prepass/prepass_bindings.rs | 0 .../src/prepass/prepass_bindings.wgsl | 0 .../src/prepass/prepass_io.wgsl | 0 .../src/prepass/prepass_utils.wgsl | 0 .../src/render/build_indirect_params.wgsl | 0 .../src/render/clustered_forward.wgsl | 0 .../src/render/fog.rs | 0 .../src/render/fog.wgsl | 0 .../src/render/forward_io.wgsl | 0 .../src/render/gpu_preprocess.rs | 0 .../src/render/light.rs | 0 .../src/render/mesh.rs | 12 +- .../src/render/mesh.wgsl | 0 .../src/render/mesh_bindings.rs | 0 .../src/render/mesh_bindings.wgsl | 0 .../src/render/mesh_functions.wgsl | 0 .../src/render/mesh_preprocess.wgsl | 0 .../src/render/mesh_types.wgsl | 0 .../src/render/mesh_view_bindings.rs | 0 .../src/render/mesh_view_bindings.wgsl | 0 .../src/render/mesh_view_types.wgsl | 0 .../src/render/mod.rs | 0 .../src/render/morph.rs | 0 .../src/render/morph.wgsl | 0 .../src/render/occlusion_culling.wgsl | 0 .../src/render/parallax_mapping.wgsl | 139 +++ crates/bevy_render_3d/src/render/pbr.wgsl | 107 +++ .../src/render/pbr_ambient.wgsl | 29 + .../src/render/pbr_bindings.wgsl | 97 ++ .../src/render/pbr_fragment.wgsl | 842 +++++++++++++++++ .../src/render/pbr_functions.wgsl | 885 ++++++++++++++++++ .../src/render/pbr_lighting.wgsl | 0 .../src/render/pbr_prepass.wgsl | 151 +++ .../src/render/pbr_prepass_functions.wgsl | 102 ++ .../src/render/pbr_transmission.wgsl | 0 .../bevy_render_3d/src/render/pbr_types.wgsl | 153 +++ .../src/render/reset_indirect_batch_sets.wgsl | 0 crates/bevy_render_3d/src/render/rgb9e5.wgsl | 63 ++ .../src/render/shadow_sampling.wgsl | 0 .../src/render/shadows.wgsl | 0 .../src/render/skin.rs | 0 .../src/render/skinning.wgsl | 0 .../src/render/utils.wgsl | 0 .../src/render/view_transformations.wgsl | 0 .../bevy_render_3d/src/render/wireframe.wgsl | 12 + .../src/ssao/mod.rs | 0 .../src/ssao/preprocess_depth.wgsl | 0 .../src/ssao/spatial_denoise.wgsl | 0 .../src/ssao/ssao.wgsl | 0 .../src/ssao/ssao_utils.wgsl | 0 .../src/ssr/mod.rs | 0 .../src/ssr/raymarch.wgsl | 0 .../src/ssr/ssr.wgsl | 0 .../src/volumetric_fog/mod.rs | 0 .../src/volumetric_fog/render.rs | 0 .../src/volumetric_fog/volumetric_fog.wgsl | 0 examples/3d/anti_aliasing.rs | 2 +- examples/3d/atmosphere.rs | 2 +- examples/3d/atmospheric_fog.rs | 2 +- examples/3d/clustered_decals.rs | 8 +- examples/3d/color_grading.rs | 2 +- examples/3d/decal.rs | 2 +- examples/3d/deferred_rendering.rs | 4 +- examples/3d/depth_of_field.rs | 2 +- examples/3d/edit_material_on_gltf.rs | 3 +- examples/3d/fog.rs | 2 +- examples/3d/fog_volumes.rs | 2 +- examples/3d/irradiance_volumes.rs | 6 +- examples/3d/lighting.rs | 2 +- examples/3d/lightmaps.rs | 2 +- examples/3d/lines.rs | 2 +- examples/3d/load_gltf.rs | 2 +- examples/3d/meshlet.rs | 6 +- examples/3d/mixed_lighting.rs | 2 +- examples/3d/pcss.rs | 2 +- examples/3d/post_processing.rs | 3 +- examples/3d/scrolling_fog.rs | 2 +- examples/3d/shadow_biases.rs | 2 +- examples/3d/shadow_caster_receiver.rs | 2 +- examples/3d/split_screen.rs | 3 +- examples/3d/spotlight.rs | 2 +- examples/3d/ssao.rs | 2 +- examples/3d/ssr.rs | 6 +- examples/3d/tonemapping.rs | 2 +- examples/3d/transmission.rs | 2 +- examples/3d/update_gltf_scene.rs | 2 +- examples/3d/visibility_range.rs | 2 +- examples/3d/volumetric_fog.rs | 2 +- examples/animation/animated_mesh.rs | 2 +- examples/animation/animated_mesh_control.rs | 2 +- examples/animation/animated_mesh_events.rs | 4 +- examples/camera/first_person_view_model.rs | 4 +- examples/shader/custom_render_phase.rs | 8 +- examples/shader/custom_shader_instancing.rs | 6 +- examples/shader/custom_vertex_attribute.rs | 2 +- examples/shader/extended_material.rs | 2 +- examples/shader/shader_defs.rs | 2 +- examples/shader/shader_material_glsl.rs | 2 +- examples/shader/shader_material_wesl.rs | 2 +- examples/shader/shader_prepass.rs | 3 +- examples/shader/specialized_mesh_pipeline.rs | 8 +- examples/stress_tests/many_cubes.rs | 2 +- examples/stress_tests/many_foxes.rs | 2 +- examples/stress_tests/many_lights.rs | 2 +- examples/tools/scene_viewer/main.rs | 2 +- 196 files changed, 3517 insertions(+), 549 deletions(-) create mode 100644 crates/bevy_render_3d/Cargo.toml create mode 100644 crates/bevy_render_3d/LICENSE-APACHE create mode 100644 crates/bevy_render_3d/LICENSE-MIT create mode 100644 crates/bevy_render_3d/README.md rename crates/{bevy_pbr => bevy_render_3d}/src/atmosphere/aerial_view_lut.wgsl (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/atmosphere/bindings.wgsl (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/atmosphere/bruneton_functions.wgsl (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/atmosphere/functions.wgsl (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/atmosphere/mod.rs (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/atmosphere/multiscattering_lut.wgsl (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/atmosphere/node.rs (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/atmosphere/render_sky.wgsl (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/atmosphere/resources.rs (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/atmosphere/sky_view_lut.wgsl (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/atmosphere/transmittance_lut.wgsl (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/atmosphere/types.wgsl (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/cluster/assign.rs (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/cluster/mod.rs (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/cluster/test.rs (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/components.rs (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/decal/clustered.rs (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/decal/clustered.wgsl (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/decal/forward.rs (91%) rename crates/{bevy_pbr => bevy_render_3d}/src/decal/forward_decal.wgsl (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/decal/mod.rs (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/deferred/deferred_lighting.wgsl (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/deferred/mod.rs (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/deferred/pbr_deferred_functions.wgsl (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/deferred/pbr_deferred_types.wgsl (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/extended_material.rs (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/fog.rs (99%) create mode 100644 crates/bevy_render_3d/src/lib.rs rename crates/{bevy_pbr => bevy_render_3d}/src/light/ambient_light.rs (91%) rename crates/{bevy_pbr => bevy_render_3d}/src/light/directional_light.rs (99%) rename crates/{bevy_pbr => bevy_render_3d}/src/light/mod.rs (98%) rename crates/{bevy_pbr => bevy_render_3d}/src/light/point_light.rs (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/light/spot_light.rs (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/light_probe/environment_map.rs (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/light_probe/environment_map.wgsl (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/light_probe/irradiance_volume.rs (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/light_probe/irradiance_volume.wgsl (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/light_probe/light_probe.wgsl (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/light_probe/mod.rs (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/lightmap/lightmap.wgsl (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/lightmap/mod.rs (97%) rename crates/{bevy_pbr => bevy_render_3d}/src/material.rs (99%) rename crates/{bevy_pbr => bevy_render_3d}/src/material_bind_groups.rs (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/mesh_material.rs (83%) rename crates/{bevy_pbr => bevy_render_3d}/src/meshlet/asset.rs (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/meshlet/clear_visibility_buffer.wgsl (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/meshlet/cull_clusters.wgsl (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/meshlet/dummy_visibility_buffer_resolve.wgsl (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/meshlet/fill_cluster_buffers.wgsl (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/meshlet/from_mesh.rs (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/meshlet/instance_manager.rs (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/meshlet/material_pipeline_prepare.rs (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/meshlet/material_shade_nodes.rs (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/meshlet/meshlet_bindings.wgsl (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/meshlet/meshlet_mesh_manager.rs (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/meshlet/meshlet_mesh_material.wgsl (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/meshlet/meshlet_preview.png (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/meshlet/mod.rs (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/meshlet/persistent_buffer.rs (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/meshlet/persistent_buffer_impls.rs (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/meshlet/pipelines.rs (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/meshlet/remap_1d_to_2d_dispatch.wgsl (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/meshlet/resolve_render_targets.wgsl (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/meshlet/resource_manager.rs (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/meshlet/visibility_buffer_hardware_raster.wgsl (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/meshlet/visibility_buffer_raster_node.rs (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/meshlet/visibility_buffer_resolve.wgsl (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/meshlet/visibility_buffer_software_raster.wgsl (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/prepass/mod.rs (98%) rename crates/{bevy_pbr => bevy_render_3d}/src/prepass/prepass.wgsl (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/prepass/prepass_bindings.rs (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/prepass/prepass_bindings.wgsl (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/prepass/prepass_io.wgsl (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/prepass/prepass_utils.wgsl (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/render/build_indirect_params.wgsl (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/render/clustered_forward.wgsl (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/render/fog.rs (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/render/fog.wgsl (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/render/forward_io.wgsl (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/render/gpu_preprocess.rs (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/render/light.rs (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/render/mesh.rs (99%) rename crates/{bevy_pbr => bevy_render_3d}/src/render/mesh.wgsl (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/render/mesh_bindings.rs (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/render/mesh_bindings.wgsl (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/render/mesh_functions.wgsl (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/render/mesh_preprocess.wgsl (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/render/mesh_types.wgsl (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/render/mesh_view_bindings.rs (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/render/mesh_view_bindings.wgsl (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/render/mesh_view_types.wgsl (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/render/mod.rs (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/render/morph.rs (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/render/morph.wgsl (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/render/occlusion_culling.wgsl (100%) create mode 100644 crates/bevy_render_3d/src/render/parallax_mapping.wgsl create mode 100644 crates/bevy_render_3d/src/render/pbr.wgsl create mode 100644 crates/bevy_render_3d/src/render/pbr_ambient.wgsl create mode 100644 crates/bevy_render_3d/src/render/pbr_bindings.wgsl create mode 100644 crates/bevy_render_3d/src/render/pbr_fragment.wgsl create mode 100644 crates/bevy_render_3d/src/render/pbr_functions.wgsl rename crates/{bevy_pbr => bevy_render_3d}/src/render/pbr_lighting.wgsl (100%) create mode 100644 crates/bevy_render_3d/src/render/pbr_prepass.wgsl create mode 100644 crates/bevy_render_3d/src/render/pbr_prepass_functions.wgsl rename crates/{bevy_pbr => bevy_render_3d}/src/render/pbr_transmission.wgsl (100%) create mode 100644 crates/bevy_render_3d/src/render/pbr_types.wgsl rename crates/{bevy_pbr => bevy_render_3d}/src/render/reset_indirect_batch_sets.wgsl (100%) create mode 100644 crates/bevy_render_3d/src/render/rgb9e5.wgsl rename crates/{bevy_pbr => bevy_render_3d}/src/render/shadow_sampling.wgsl (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/render/shadows.wgsl (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/render/skin.rs (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/render/skinning.wgsl (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/render/utils.wgsl (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/render/view_transformations.wgsl (100%) create mode 100644 crates/bevy_render_3d/src/render/wireframe.wgsl rename crates/{bevy_pbr => bevy_render_3d}/src/ssao/mod.rs (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/ssao/preprocess_depth.wgsl (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/ssao/spatial_denoise.wgsl (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/ssao/ssao.wgsl (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/ssao/ssao_utils.wgsl (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/ssr/mod.rs (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/ssr/raymarch.wgsl (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/ssr/ssr.wgsl (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/volumetric_fog/mod.rs (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/volumetric_fog/render.rs (100%) rename crates/{bevy_pbr => bevy_render_3d}/src/volumetric_fog/volumetric_fog.wgsl (100%) diff --git a/Cargo.toml b/Cargo.toml index af2d9d356cb59..540008bcc252a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -143,6 +143,7 @@ default = [ "bevy_pbr", "bevy_picking", "bevy_render", + "bevy_render_3d", "bevy_scene", "bevy_sprite", "bevy_sprite_picking_backend", @@ -242,6 +243,9 @@ bevy_picking = ["bevy_internal/bevy_picking"] # Provides rendering functionality bevy_render = ["bevy_internal/bevy_render", "bevy_color"] +# Provides functionality for rendering in 3d +bevy_render_3d = ["bevy_internal/bevy_render_3d"] + # Provides scene functionality bevy_scene = ["bevy_internal/bevy_scene", "bevy_asset"] diff --git a/crates/bevy_gizmos/Cargo.toml b/crates/bevy_gizmos/Cargo.toml index 3a264c6244609..5cc625d09b74c 100644 --- a/crates/bevy_gizmos/Cargo.toml +++ b/crates/bevy_gizmos/Cargo.toml @@ -15,7 +15,6 @@ bevy_render = ["dep:bevy_render", "bevy_core_pipeline"] [dependencies] # Bevy -bevy_pbr = { path = "../bevy_pbr", version = "0.16.0-dev", optional = true } bevy_sprite = { path = "../bevy_sprite", version = "0.16.0-dev", optional = true } bevy_app = { path = "../bevy_app", version = "0.16.0-dev" } bevy_color = { path = "../bevy_color", version = "0.16.0-dev" } @@ -24,6 +23,7 @@ bevy_image = { path = "../bevy_image", version = "0.16.0-dev" } bevy_math = { path = "../bevy_math", version = "0.16.0-dev" } bevy_asset = { path = "../bevy_asset", version = "0.16.0-dev" } bevy_render = { path = "../bevy_render", version = "0.16.0-dev", optional = true } +bevy_render_3d = { path = "../bevy_render_3d", version = "0.16.0-dev", optional = true } bevy_utils = { path = "../bevy_utils", version = "0.16.0-dev" } bevy_reflect = { path = "../bevy_reflect", version = "0.16.0-dev" } bevy_core_pipeline = { path = "../bevy_core_pipeline", version = "0.16.0-dev", optional = true } diff --git a/crates/bevy_gizmos/src/config.rs b/crates/bevy_gizmos/src/config.rs index 973fa1cf0fbce..de504d2d384b9 100644 --- a/crates/bevy_gizmos/src/config.rs +++ b/crates/bevy_gizmos/src/config.rs @@ -4,7 +4,7 @@ pub use bevy_gizmos_macros::GizmoConfigGroup; #[cfg(all( feature = "bevy_render", - any(feature = "bevy_pbr", feature = "bevy_sprite") + any(feature = "bevy_render_3d", feature = "bevy_sprite") ))] use {crate::GizmoAsset, bevy_asset::Handle, bevy_ecs::component::Component}; @@ -246,7 +246,7 @@ impl Default for GizmoLineConfig { #[cfg(all( feature = "bevy_render", - any(feature = "bevy_pbr", feature = "bevy_sprite") + any(feature = "bevy_render_3d", feature = "bevy_sprite") ))] #[derive(Component)] pub(crate) struct GizmoMeshConfig { diff --git a/crates/bevy_gizmos/src/lib.rs b/crates/bevy_gizmos/src/lib.rs index 3cd2c7c40447a..a56e6ae32f802 100755 --- a/crates/bevy_gizmos/src/lib.rs +++ b/crates/bevy_gizmos/src/lib.rs @@ -29,7 +29,7 @@ pub enum GizmoRenderSystem { #[cfg(feature = "bevy_sprite")] QueueLineGizmos2d, /// Adds gizmos to the [`Transparent3d`](bevy_core_pipeline::core_3d::Transparent3d) render phase - #[cfg(feature = "bevy_pbr")] + #[cfg(feature = "bevy_render_3d")] QueueLineGizmos3d, } @@ -47,12 +47,12 @@ pub mod primitives; pub mod retained; pub mod rounded_box; -#[cfg(all(feature = "bevy_pbr", feature = "bevy_render"))] +#[cfg(all(feature = "bevy_render_3d", feature = "bevy_render"))] pub mod light; #[cfg(all(feature = "bevy_sprite", feature = "bevy_render"))] mod pipeline_2d; -#[cfg(all(feature = "bevy_pbr", feature = "bevy_render"))] +#[cfg(all(feature = "bevy_render_3d", feature = "bevy_render"))] mod pipeline_3d; /// The gizmos prelude. @@ -74,7 +74,7 @@ pub mod prelude { AppGizmoBuilder, GizmoAsset, }; - #[cfg(all(feature = "bevy_pbr", feature = "bevy_render"))] + #[cfg(all(feature = "bevy_render_3d", feature = "bevy_render"))] pub use crate::light::{LightGizmoColor, LightGizmoConfigGroup, ShowLightGizmo}; } @@ -89,7 +89,7 @@ use bevy_reflect::TypePath; #[cfg(all( feature = "bevy_render", - any(feature = "bevy_pbr", feature = "bevy_sprite") + any(feature = "bevy_render_3d", feature = "bevy_sprite") ))] use crate::config::GizmoMeshConfig; @@ -127,7 +127,7 @@ use { #[cfg(all( feature = "bevy_render", - any(feature = "bevy_pbr", feature = "bevy_sprite"), + any(feature = "bevy_render_3d", feature = "bevy_sprite"), ))] use bevy_render::render_resource::{VertexAttribute, VertexBufferLayout, VertexStepMode}; use bevy_time::Fixed; @@ -137,7 +137,7 @@ use config::GizmoLineJoint; use config::{DefaultGizmoConfigGroup, GizmoConfig, GizmoConfigGroup, GizmoConfigStore}; use core::{any::TypeId, marker::PhantomData, mem}; use gizmos::{GizmoStorage, Swap}; -#[cfg(all(feature = "bevy_pbr", feature = "bevy_render"))] +#[cfg(all(feature = "bevy_render_3d", feature = "bevy_render"))] use light::LightGizmoPlugin; #[cfg(feature = "bevy_render")] @@ -148,7 +148,7 @@ const LINE_JOINT_SHADER_HANDLE: Handle = /// A [`Plugin`] that provides an immediate mode drawing api for visual debugging. /// -/// Requires to be loaded after [`PbrPlugin`](bevy_pbr::PbrPlugin) or [`SpritePlugin`](bevy_sprite::SpritePlugin). +/// Requires to be loaded after [`MeshPipelinePlugin`](bevy_render_3d::MeshPipelinePlugin) or [`SpritePlugin`](bevy_sprite::SpritePlugin). #[derive(Default)] pub struct GizmoPlugin; @@ -178,7 +178,7 @@ impl Plugin for GizmoPlugin { .add_plugins(UniformComponentPlugin::::default()) .add_plugins(RenderAssetPlugin::::default()); - #[cfg(all(feature = "bevy_pbr", feature = "bevy_render"))] + #[cfg(all(feature = "bevy_render_3d", feature = "bevy_render"))] app.add_plugins(LightGizmoPlugin); #[cfg(feature = "bevy_render")] @@ -196,11 +196,11 @@ impl Plugin for GizmoPlugin { } else { tracing::warn!("bevy_sprite feature is enabled but bevy_sprite::SpritePlugin was not detected. Are you sure you loaded GizmoPlugin after SpritePlugin?"); } - #[cfg(feature = "bevy_pbr")] - if app.is_plugin_added::() { + #[cfg(feature = "bevy_render_3d")] + if app.is_plugin_added::() { app.add_plugins(pipeline_3d::LineGizmo3dPlugin); } else { - tracing::warn!("bevy_pbr feature is enabled but bevy_pbr::PbrPlugin was not detected. Are you sure you loaded GizmoPlugin after PbrPlugin?"); + tracing::warn!("bevy_render_3d feature is enabled but bevy_render_3d::PbrPlugin was not detected. Are you sure you loaded GizmoPlugin after PbrPlugin?"); } } else { tracing::warn!("bevy_render feature is enabled but RenderApp was not detected. Are you sure you loaded GizmoPlugin after RenderPlugin?"); @@ -474,7 +474,7 @@ fn extract_gizmo_data( #[cfg(feature = "webgl")] _padding: Default::default(), }, - #[cfg(any(feature = "bevy_pbr", feature = "bevy_sprite"))] + #[cfg(any(feature = "bevy_render_3d", feature = "bevy_sprite"))] GizmoMeshConfig { line_perspective: config.line.perspective, line_style: config.line.style, @@ -655,7 +655,7 @@ impl RenderCommand

for SetLineGizmoBindGroup struct DrawLineGizmo; #[cfg(all( feature = "bevy_render", - any(feature = "bevy_pbr", feature = "bevy_sprite") + any(feature = "bevy_render_3d", feature = "bevy_sprite") ))] impl RenderCommand

for DrawLineGizmo { type Param = SRes>; @@ -718,7 +718,7 @@ impl RenderCommand

for DrawLineGizmo struct DrawLineJointGizmo; #[cfg(all( feature = "bevy_render", - any(feature = "bevy_pbr", feature = "bevy_sprite") + any(feature = "bevy_render_3d", feature = "bevy_sprite") ))] impl RenderCommand

for DrawLineJointGizmo { type Param = SRes>; @@ -791,7 +791,7 @@ impl RenderCommand

for DrawLineJointGizmo { #[cfg(all( feature = "bevy_render", - any(feature = "bevy_pbr", feature = "bevy_sprite") + any(feature = "bevy_render_3d", feature = "bevy_sprite") ))] fn line_gizmo_vertex_buffer_layouts(strip: bool) -> Vec { use VertexFormat::*; @@ -849,7 +849,7 @@ fn line_gizmo_vertex_buffer_layouts(strip: bool) -> Vec { #[cfg(all( feature = "bevy_render", - any(feature = "bevy_pbr", feature = "bevy_sprite") + any(feature = "bevy_render_3d", feature = "bevy_sprite") ))] fn line_joint_gizmo_vertex_buffer_layouts() -> Vec { use VertexFormat::*; diff --git a/crates/bevy_gizmos/src/light.rs b/crates/bevy_gizmos/src/light.rs index 7f7dadacc26ec..5415f9e9a2a81 100644 --- a/crates/bevy_gizmos/src/light.rs +++ b/crates/bevy_gizmos/src/light.rs @@ -22,8 +22,8 @@ use bevy_math::{ primitives::{Cone, Sphere}, Isometry3d, Quat, Vec3, }; -use bevy_pbr::{DirectionalLight, PointLight, SpotLight}; use bevy_reflect::{std_traits::ReflectDefault, Reflect}; +use bevy_render_3d::{DirectionalLight, PointLight, SpotLight}; use bevy_transform::{components::GlobalTransform, TransformSystem}; use crate::{ diff --git a/crates/bevy_gizmos/src/pipeline_3d.rs b/crates/bevy_gizmos/src/pipeline_3d.rs index 799793e6cbba6..0b3238dfeb151 100644 --- a/crates/bevy_gizmos/src/pipeline_3d.rs +++ b/crates/bevy_gizmos/src/pipeline_3d.rs @@ -20,7 +20,6 @@ use bevy_ecs::{ world::{FromWorld, World}, }; use bevy_image::BevyDefault as _; -use bevy_pbr::{MeshPipeline, MeshPipelineKey, SetMeshViewBindGroup}; use bevy_render::sync_world::MainEntity; use bevy_render::{ render_asset::{prepare_assets, RenderAssets}, @@ -32,6 +31,7 @@ use bevy_render::{ view::{ExtractedView, Msaa, RenderLayers, ViewTarget}, Render, RenderApp, RenderSet, }; +use bevy_render_3d::{MeshPipeline, MeshPipelineKey, SetMeshViewBindGroup}; use tracing::error; pub struct LineGizmo3dPlugin; @@ -51,7 +51,7 @@ impl Plugin for LineGizmo3dPlugin { Render, GizmoRenderSystem::QueueLineGizmos3d .in_set(RenderSet::Queue) - .ambiguous_with(bevy_pbr::queue_material_meshes::), + .ambiguous_with(RenderSet::QueueMeshes), ) .add_systems( Render, diff --git a/crates/bevy_gizmos/src/retained.rs b/crates/bevy_gizmos/src/retained.rs index 88610b9744203..7c9f4506268e2 100644 --- a/crates/bevy_gizmos/src/retained.rs +++ b/crates/bevy_gizmos/src/retained.rs @@ -143,7 +143,7 @@ pub(crate) fn extract_linegizmos( #[cfg(feature = "webgl")] _padding: Default::default(), }, - #[cfg(any(feature = "bevy_pbr", feature = "bevy_sprite"))] + #[cfg(any(feature = "bevy_render_3d", feature = "bevy_sprite"))] crate::config::GizmoMeshConfig { line_perspective: gizmo.line_config.perspective, line_style: gizmo.line_config.style, diff --git a/crates/bevy_gltf/Cargo.toml b/crates/bevy_gltf/Cargo.toml index 48adba2fd29ec..36787f254f1eb 100644 --- a/crates/bevy_gltf/Cargo.toml +++ b/crates/bevy_gltf/Cargo.toml @@ -30,6 +30,7 @@ bevy_mesh = { path = "../bevy_mesh", version = "0.16.0-dev" } bevy_pbr = { path = "../bevy_pbr", version = "0.16.0-dev" } bevy_reflect = { path = "../bevy_reflect", version = "0.16.0-dev" } bevy_render = { path = "../bevy_render", version = "0.16.0-dev" } +bevy_render_3d = { path = "../bevy_render_3d", version = "0.16.0-dev" } bevy_scene = { path = "../bevy_scene", version = "0.16.0-dev", features = [ "bevy_render", ] } diff --git a/crates/bevy_gltf/src/loader/mod.rs b/crates/bevy_gltf/src/loader/mod.rs index 882626af881da..4bd8424ecb378 100644 --- a/crates/bevy_gltf/src/loader/mod.rs +++ b/crates/bevy_gltf/src/loader/mod.rs @@ -30,11 +30,9 @@ use bevy_mesh::{ skinning::{SkinnedMesh, SkinnedMeshInverseBindposes}, Indices, Mesh, MeshVertexAttribute, PrimitiveTopology, VertexAttributeValues, }; +use bevy_pbr::StandardMaterial; #[cfg(feature = "pbr_transmission_textures")] use bevy_pbr::UvChannel; -use bevy_pbr::{ - DirectionalLight, MeshMaterial3d, PointLight, SpotLight, StandardMaterial, MAX_JOINTS, -}; use bevy_platform_support::collections::{HashMap, HashSet}; use bevy_render::{ camera::{Camera, OrthographicProjection, PerspectiveProjection, Projection, ScalingMode}, @@ -43,6 +41,7 @@ use bevy_render::{ render_resource::Face, view::Visibility, }; +use bevy_render_3d::{DirectionalLight, MeshMaterial3d, PointLight, SpotLight, MAX_JOINTS}; use bevy_scene::Scene; #[cfg(not(target_arch = "wasm32"))] use bevy_tasks::IoTaskPool; diff --git a/crates/bevy_internal/Cargo.toml b/crates/bevy_internal/Cargo.toml index e99ac30238584..ea307475c46a8 100644 --- a/crates/bevy_internal/Cargo.toml +++ b/crates/bevy_internal/Cargo.toml @@ -171,7 +171,7 @@ bevy_ci_testing = ["bevy_dev_tools/bevy_ci_testing", "bevy_render?/ci_limits"] animation = ["bevy_animation", "bevy_gltf?/bevy_animation"] bevy_sprite = ["dep:bevy_sprite", "bevy_gizmos?/bevy_sprite", "bevy_image"] -bevy_pbr = ["dep:bevy_pbr", "bevy_gizmos?/bevy_pbr", "bevy_image"] +bevy_pbr = ["dep:bevy_pbr", "bevy_image"] bevy_window = ["dep:bevy_window", "dep:bevy_a11y"] bevy_core_pipeline = ["dep:bevy_core_pipeline", "bevy_image"] bevy_anti_aliasing = ["dep:bevy_anti_aliasing", "bevy_image"] @@ -200,6 +200,7 @@ bevy_render = [ "bevy_color/wgpu-types", "bevy_color/encase", ] +bevy_render_3d = ["dep:bevy_render_3d", "bevy_gizmos?/bevy_render_3d"] # Enable assertions to check the validity of parameters passed to glam glam_assert = ["bevy_math/glam_assert"] @@ -412,6 +413,7 @@ bevy_pbr = { path = "../bevy_pbr", optional = true, version = "0.16.0-dev" } bevy_picking = { path = "../bevy_picking", optional = true, version = "0.16.0-dev" } bevy_remote = { path = "../bevy_remote", optional = true, version = "0.16.0-dev" } bevy_render = { path = "../bevy_render", optional = true, version = "0.16.0-dev" } +bevy_render_3d = { path = "../bevy_render_3d", optional = true, version = "0.16.0-dev" } bevy_scene = { path = "../bevy_scene", optional = true, version = "0.16.0-dev" } bevy_sprite = { path = "../bevy_sprite", optional = true, version = "0.16.0-dev" } bevy_state = { path = "../bevy_state", optional = true, version = "0.16.0-dev", default-features = false, features = [ diff --git a/crates/bevy_internal/src/default_plugins.rs b/crates/bevy_internal/src/default_plugins.rs index e82378eb91437..5cf6e58dc9e30 100644 --- a/crates/bevy_internal/src/default_plugins.rs +++ b/crates/bevy_internal/src/default_plugins.rs @@ -40,6 +40,8 @@ plugin_group! { bevy_render::pipelined_rendering:::PipelinedRenderingPlugin, #[cfg(feature = "bevy_core_pipeline")] bevy_core_pipeline:::CorePipelinePlugin, + #[cfg(feature = "bevy_render_3d")] + bevy_render_3d:::MeshPipelinePlugin, #[cfg(feature = "bevy_anti_aliasing")] bevy_anti_aliasing:::AntiAliasingPlugin, #[cfg(feature = "bevy_sprite")] diff --git a/crates/bevy_internal/src/lib.rs b/crates/bevy_internal/src/lib.rs index bd8615e1a12ae..f8989d9f1af77 100644 --- a/crates/bevy_internal/src/lib.rs +++ b/crates/bevy_internal/src/lib.rs @@ -60,6 +60,8 @@ pub use bevy_reflect as reflect; pub use bevy_remote as remote; #[cfg(feature = "bevy_render")] pub use bevy_render as render; +#[cfg(feature = "bevy_render_3d")] +pub use bevy_render_3d as render_3d; #[cfg(feature = "bevy_scene")] pub use bevy_scene as scene; #[cfg(feature = "bevy_sprite")] diff --git a/crates/bevy_internal/src/prelude.rs b/crates/bevy_internal/src/prelude.rs index a01cc4da2c6d9..c2a37155b0eef 100644 --- a/crates/bevy_internal/src/prelude.rs +++ b/crates/bevy_internal/src/prelude.rs @@ -50,6 +50,10 @@ pub use crate::pbr::prelude::*; #[cfg(feature = "bevy_render")] pub use crate::render::prelude::*; +#[doc(hidden)] +#[cfg(feature = "bevy_render_3d")] +pub use crate::render_3d::prelude::*; + #[doc(hidden)] #[cfg(feature = "bevy_scene")] pub use crate::scene::prelude::*; diff --git a/crates/bevy_pbr/Cargo.toml b/crates/bevy_pbr/Cargo.toml index 9b9860b60f6b0..ada9f68d9e45c 100644 --- a/crates/bevy_pbr/Cargo.toml +++ b/crates/bevy_pbr/Cargo.toml @@ -42,6 +42,7 @@ bevy_image = { path = "../bevy_image", version = "0.16.0-dev" } bevy_math = { path = "../bevy_math", version = "0.16.0-dev" } bevy_reflect = { path = "../bevy_reflect", version = "0.16.0-dev" } bevy_render = { path = "../bevy_render", version = "0.16.0-dev" } +bevy_render_3d = { path = "../bevy_render_3d", version = "0.16.0-dev" } bevy_tasks = { path = "../bevy_tasks", version = "0.16.0-dev", optional = true } bevy_transform = { path = "../bevy_transform", version = "0.16.0-dev" } bevy_utils = { path = "../bevy_utils", version = "0.16.0-dev" } diff --git a/crates/bevy_pbr/src/lib.rs b/crates/bevy_pbr/src/lib.rs index fdfcdc7b48351..977eb94e699b9 100644 --- a/crates/bevy_pbr/src/lib.rs +++ b/crates/bevy_pbr/src/lib.rs @@ -8,192 +8,50 @@ extern crate alloc; -#[cfg(feature = "meshlet")] -mod meshlet; pub mod wireframe; -/// Experimental features that are not yet finished. Please report any issues you encounter! -/// -/// Expect bugs, missing features, compatibility issues, low performance, and/or future breaking changes. -#[cfg(feature = "meshlet")] -pub mod experimental { - /// Render high-poly 3d meshes using an efficient GPU-driven method. - /// See [`MeshletPlugin`](meshlet::MeshletPlugin) and [`MeshletMesh`](meshlet::MeshletMesh) for details. - pub mod meshlet { - pub use crate::meshlet::*; - } -} - -mod atmosphere; -mod cluster; -mod components; -pub mod decal; -pub mod deferred; -mod extended_material; -mod fog; -mod light; -mod light_probe; -mod lightmap; -mod material; -mod material_bind_groups; -mod mesh_material; mod parallax; mod pbr_material; -mod prepass; -mod render; -mod ssao; -mod ssr; -mod volumetric_fog; - -use bevy_color::{Color, LinearRgba}; -pub use atmosphere::*; -pub use cluster::*; -pub use components::*; -pub use decal::clustered::ClusteredDecalPlugin; -pub use extended_material::*; -pub use fog::*; -pub use light::*; -pub use light_probe::*; -pub use lightmap::*; -pub use material::*; -pub use material_bind_groups::*; -pub use mesh_material::*; pub use parallax::*; pub use pbr_material::*; -pub use prepass::*; -pub use render::*; -pub use ssao::*; -pub use ssr::*; -pub use volumetric_fog::{FogVolume, VolumetricFog, VolumetricFogPlugin, VolumetricLight}; /// The PBR prelude. /// /// This includes the most common types in this crate, re-exported for your convenience. pub mod prelude { #[doc(hidden)] - pub use crate::{ - fog::{DistanceFog, FogFalloff}, - light::{light_consts, AmbientLight, DirectionalLight, PointLight, SpotLight}, - light_probe::{environment_map::EnvironmentMapLight, LightProbe}, - material::{Material, MaterialPlugin}, - mesh_material::MeshMaterial3d, - parallax::ParallaxMappingMethod, - pbr_material::StandardMaterial, - ssao::ScreenSpaceAmbientOcclusionPlugin, - }; -} - -pub mod graph { - use bevy_render::render_graph::RenderLabel; - - /// Render graph nodes specific to 3D PBR rendering. - #[derive(Debug, Hash, PartialEq, Eq, Clone, RenderLabel)] - pub enum NodePbr { - /// Label for the shadow pass node that draws meshes that were visible - /// from the light last frame. - EarlyShadowPass, - /// Label for the shadow pass node that draws meshes that became visible - /// from the light this frame. - LateShadowPass, - /// Label for the screen space ambient occlusion render node. - ScreenSpaceAmbientOcclusion, - DeferredLightingPass, - /// Label for the volumetric lighting pass. - VolumetricFog, - /// Label for the shader that transforms and culls meshes that were - /// visible last frame. - EarlyGpuPreprocess, - /// Label for the shader that transforms and culls meshes that became - /// visible this frame. - LateGpuPreprocess, - /// Label for the screen space reflections pass. - ScreenSpaceReflections, - /// Label for the node that builds indirect draw parameters for meshes - /// that were visible last frame. - EarlyPrepassBuildIndirectParameters, - /// Label for the node that builds indirect draw parameters for meshes - /// that became visible this frame. - LatePrepassBuildIndirectParameters, - /// Label for the node that builds indirect draw parameters for the main - /// rendering pass, containing all meshes that are visible this frame. - MainBuildIndirectParameters, - ClearIndirectParametersMetadata, - } + pub use crate::{parallax::ParallaxMappingMethod, pbr_material::StandardMaterial}; } -use crate::{deferred::DeferredPbrLightingPlugin, graph::NodePbr}; -use bevy_app::prelude::*; +use bevy_app::{App, Plugin}; use bevy_asset::{load_internal_asset, weak_handle, AssetApp, Assets, Handle}; -use bevy_core_pipeline::core_3d::graph::{Core3d, Node3d}; -use bevy_ecs::prelude::*; -use bevy_image::Image; -use bevy_render::{ - alpha::AlphaMode, - camera::{sort_cameras, CameraUpdateSystem, Projection}, - extract_component::ExtractComponentPlugin, - extract_resource::ExtractResourcePlugin, - render_graph::RenderGraph, - render_resource::Shader, - sync_component::SyncComponentPlugin, - view::VisibilitySystems, - ExtractSchedule, Render, RenderApp, RenderDebugFlags, RenderSet, -}; +use bevy_color::Color; +use bevy_render::{render_resource::Shader, RenderDebugFlags}; +use bevy_render_3d::{decal::ForwardDecalPlugin, MaterialPlugin}; -use bevy_transform::TransformSystem; - -pub const PBR_TYPES_SHADER_HANDLE: Handle = +const PBR_TYPES_SHADER_HANDLE: Handle = weak_handle!("b0330585-2335-4268-9032-a6c4c2d932f6"); -pub const PBR_BINDINGS_SHADER_HANDLE: Handle = +const PBR_BINDINGS_SHADER_HANDLE: Handle = weak_handle!("13834c18-c7ec-4c4b-bbbd-432c3ba4cace"); -pub const UTILS_HANDLE: Handle = weak_handle!("0a32978f-2744-4608-98b6-4c3000a0638d"); -pub const CLUSTERED_FORWARD_HANDLE: Handle = - weak_handle!("f8e3b4c6-60b7-4b23-8b2e-a6b27bb4ddce"); -pub const PBR_LIGHTING_HANDLE: Handle = - weak_handle!("de0cf697-2876-49a0-aa0f-f015216f70c2"); -pub const PBR_TRANSMISSION_HANDLE: Handle = - weak_handle!("22482185-36bb-4c16-9b93-a20e6d4a2725"); -pub const SHADOWS_HANDLE: Handle = weak_handle!("ff758c5a-3927-4a15-94c3-3fbdfc362590"); -pub const SHADOW_SAMPLING_HANDLE: Handle = - weak_handle!("f6bf5843-54bc-4e39-bd9d-56bfcd77b033"); -pub const PBR_FRAGMENT_HANDLE: Handle = - weak_handle!("1bd3c10d-851b-400c-934a-db489d99cc50"); -pub const PBR_SHADER_HANDLE: Handle = weak_handle!("0eba65ed-3e5b-4752-93ed-e8097e7b0c84"); -pub const PBR_PREPASS_SHADER_HANDLE: Handle = +const PBR_FRAGMENT_HANDLE: Handle = weak_handle!("1bd3c10d-851b-400c-934a-db489d99cc50"); +const PBR_SHADER_HANDLE: Handle = weak_handle!("0eba65ed-3e5b-4752-93ed-e8097e7b0c84"); +const PBR_PREPASS_SHADER_HANDLE: Handle = weak_handle!("9afeaeab-7c45-43ce-b322-4b97799eaeb9"); -pub const PBR_FUNCTIONS_HANDLE: Handle = - weak_handle!("815b8618-f557-4a96-91a5-a2fb7e249fb0"); -pub const PBR_AMBIENT_HANDLE: Handle = weak_handle!("4a90b95b-112a-4a10-9145-7590d6f14260"); -pub const PARALLAX_MAPPING_SHADER_HANDLE: Handle = +const PBR_FUNCTIONS_HANDLE: Handle = weak_handle!("815b8618-f557-4a96-91a5-a2fb7e249fb0"); +const PBR_AMBIENT_HANDLE: Handle = weak_handle!("4a90b95b-112a-4a10-9145-7590d6f14260"); +const PARALLAX_MAPPING_SHADER_HANDLE: Handle = weak_handle!("6cf57d9f-222a-429a-bba4-55ba9586e1d4"); -pub const VIEW_TRANSFORMATIONS_SHADER_HANDLE: Handle = - weak_handle!("ec047703-cde3-4876-94df-fed121544abb"); -pub const PBR_PREPASS_FUNCTIONS_SHADER_HANDLE: Handle = +const PBR_PREPASS_FUNCTIONS_SHADER_HANDLE: Handle = weak_handle!("77b1bd3a-877c-4b2c-981b-b9c68d1b774a"); -pub const PBR_DEFERRED_TYPES_HANDLE: Handle = - weak_handle!("43060da7-a717-4240-80a8-dbddd92bd25d"); -pub const PBR_DEFERRED_FUNCTIONS_HANDLE: Handle = - weak_handle!("9dc46746-c51d-45e3-a321-6a50c3963420"); -pub const RGB9E5_FUNCTIONS_HANDLE: Handle = +const RGB9E5_FUNCTIONS_HANDLE: Handle = weak_handle!("90c19aa3-6a11-4252-8586-d9299352e94f"); -const MESHLET_VISIBILITY_BUFFER_RESOLVE_SHADER_HANDLE: Handle = - weak_handle!("69187376-3dea-4d0f-b3f5-185bde63d6a2"); - -pub const TONEMAPPING_LUT_TEXTURE_BINDING_INDEX: u32 = 26; -pub const TONEMAPPING_LUT_SAMPLER_BINDING_INDEX: u32 = 27; /// Sets up the entire PBR infrastructure of bevy. pub struct PbrPlugin { /// Controls if the prepass is enabled for the [`StandardMaterial`]. /// For more information about what a prepass is, see the [`bevy_core_pipeline::prepass`] docs. pub prepass_enabled: bool, - /// Controls if [`DeferredPbrLightingPlugin`] is added. - pub add_default_deferred_lighting_plugin: bool, - /// Controls if GPU [`MeshUniform`] building is enabled. - /// - /// This requires compute shader support and so will be forcibly disabled if - /// the platform doesn't support those. - pub use_gpu_instance_buffer_builder: bool, /// Debugging flags that can optionally be set when constructing the renderer. pub debug_flags: RenderDebugFlags, } @@ -202,8 +60,6 @@ impl Default for PbrPlugin { fn default() -> Self { Self { prepass_enabled: true, - add_default_deferred_lighting_plugin: true, - use_gpu_instance_buffer_builder: true, debug_flags: RenderDebugFlags::default(), } } @@ -223,49 +79,6 @@ impl Plugin for PbrPlugin { "render/pbr_bindings.wgsl", Shader::from_wgsl ); - load_internal_asset!(app, UTILS_HANDLE, "render/utils.wgsl", Shader::from_wgsl); - load_internal_asset!( - app, - CLUSTERED_FORWARD_HANDLE, - "render/clustered_forward.wgsl", - Shader::from_wgsl - ); - load_internal_asset!( - app, - PBR_LIGHTING_HANDLE, - "render/pbr_lighting.wgsl", - Shader::from_wgsl - ); - load_internal_asset!( - app, - PBR_TRANSMISSION_HANDLE, - "render/pbr_transmission.wgsl", - Shader::from_wgsl - ); - load_internal_asset!( - app, - SHADOWS_HANDLE, - "render/shadows.wgsl", - Shader::from_wgsl - ); - load_internal_asset!( - app, - PBR_DEFERRED_TYPES_HANDLE, - "deferred/pbr_deferred_types.wgsl", - Shader::from_wgsl - ); - load_internal_asset!( - app, - PBR_DEFERRED_FUNCTIONS_HANDLE, - "deferred/pbr_deferred_functions.wgsl", - Shader::from_wgsl - ); - load_internal_asset!( - app, - SHADOW_SAMPLING_HANDLE, - "render/shadow_sampling.wgsl", - Shader::from_wgsl - ); load_internal_asset!( app, PBR_FUNCTIONS_HANDLE, @@ -309,145 +122,16 @@ impl Plugin for PbrPlugin { "render/parallax_mapping.wgsl", Shader::from_wgsl ); - load_internal_asset!( - app, - VIEW_TRANSFORMATIONS_SHADER_HANDLE, - "render/view_transformations.wgsl", - Shader::from_wgsl - ); - // Setup dummy shaders for when MeshletPlugin is not used to prevent shader import errors. - load_internal_asset!( - app, - MESHLET_VISIBILITY_BUFFER_RESOLVE_SHADER_HANDLE, - "meshlet/dummy_visibility_buffer_resolve.wgsl", - Shader::from_wgsl - ); app.register_asset_reflect::() - .register_type::() - .register_type::() - .register_type::() - .register_type::() - .register_type::() - .register_type::() - .register_type::() - .register_type::() - .register_type::() - .register_type::() - .register_type::() - .register_type::() - .register_type::() - .register_type::() - .register_type::() - .init_resource::() - .init_resource::() - .init_resource::() - .init_resource::() - .register_type::() - .init_resource::() .add_plugins(( - MeshRenderPlugin { - use_gpu_instance_buffer_builder: self.use_gpu_instance_buffer_builder, - debug_flags: self.debug_flags, - }, MaterialPlugin:: { prepass_enabled: self.prepass_enabled, debug_flags: self.debug_flags, ..Default::default() }, - ScreenSpaceAmbientOcclusionPlugin, - ExtractResourcePlugin::::default(), - FogPlugin, - ExtractResourcePlugin::::default(), - ExtractComponentPlugin::::default(), - LightmapPlugin, - LightProbePlugin, - PbrProjectionPlugin, - GpuMeshPreprocessPlugin { - use_gpu_instance_buffer_builder: self.use_gpu_instance_buffer_builder, - }, - VolumetricFogPlugin, - ScreenSpaceReflectionsPlugin, - ClusteredDecalPlugin, - )) - .add_plugins(( - decal::ForwardDecalPlugin, - SyncComponentPlugin::::default(), - SyncComponentPlugin::::default(), - SyncComponentPlugin::::default(), - ExtractComponentPlugin::::default(), - )) - .add_plugins(AtmospherePlugin) - .configure_sets( - PostUpdate, - ( - SimulationLightSystems::AddClusters, - SimulationLightSystems::AssignLightsToClusters, - ) - .chain(), - ) - .configure_sets( - PostUpdate, - SimulationLightSystems::UpdateDirectionalLightCascades - .ambiguous_with(SimulationLightSystems::UpdateDirectionalLightCascades), - ) - .configure_sets( - PostUpdate, - SimulationLightSystems::CheckLightVisibility - .ambiguous_with(SimulationLightSystems::CheckLightVisibility), - ) - .add_systems( - PostUpdate, - ( - add_clusters - .in_set(SimulationLightSystems::AddClusters) - .after(CameraUpdateSystem), - assign_objects_to_clusters - .in_set(SimulationLightSystems::AssignLightsToClusters) - .after(TransformSystem::TransformPropagate) - .after(VisibilitySystems::CheckVisibility) - .after(CameraUpdateSystem), - clear_directional_light_cascades - .in_set(SimulationLightSystems::UpdateDirectionalLightCascades) - .after(TransformSystem::TransformPropagate) - .after(CameraUpdateSystem), - update_directional_light_frusta - .in_set(SimulationLightSystems::UpdateLightFrusta) - // This must run after CheckVisibility because it relies on `ViewVisibility` - .after(VisibilitySystems::CheckVisibility) - .after(TransformSystem::TransformPropagate) - .after(SimulationLightSystems::UpdateDirectionalLightCascades) - // We assume that no entity will be both a directional light and a spot light, - // so these systems will run independently of one another. - // FIXME: Add an archetype invariant for this https://github.com/bevyengine/bevy/issues/1481. - .ambiguous_with(update_spot_light_frusta), - update_point_light_frusta - .in_set(SimulationLightSystems::UpdateLightFrusta) - .after(TransformSystem::TransformPropagate) - .after(SimulationLightSystems::AssignLightsToClusters), - update_spot_light_frusta - .in_set(SimulationLightSystems::UpdateLightFrusta) - .after(TransformSystem::TransformPropagate) - .after(SimulationLightSystems::AssignLightsToClusters), - ( - check_dir_light_mesh_visibility, - check_point_light_mesh_visibility, - ) - .in_set(SimulationLightSystems::CheckLightVisibility) - .after(VisibilitySystems::CalculateBounds) - .after(TransformSystem::TransformPropagate) - .after(SimulationLightSystems::UpdateLightFrusta) - // NOTE: This MUST be scheduled AFTER the core renderer visibility check - // because that resets entity `ViewVisibility` for the first view - // which would override any results from this otherwise - .after(VisibilitySystems::CheckVisibility) - .before(VisibilitySystems::MarkNewlyHiddenEntitiesInvisible), - ), - ); - - if self.add_default_deferred_lighting_plugin { - app.add_plugins(DeferredPbrLightingPlugin); - } + ForwardDecalPlugin::::default(), + )); // Initialize the default material handle. app.world_mut() @@ -459,68 +143,5 @@ impl Plugin for PbrPlugin { ..Default::default() }, ); - - let Some(render_app) = app.get_sub_app_mut(RenderApp) else { - return; - }; - - // Extract the required data from the main world - render_app - .add_systems(ExtractSchedule, (extract_clusters, extract_lights)) - .add_systems( - Render, - ( - prepare_lights - .in_set(RenderSet::ManageViews) - .after(sort_cameras), - prepare_clusters.in_set(RenderSet::PrepareResources), - ), - ) - .init_resource::() - .init_resource::(); - - render_app.world_mut().add_observer(add_light_view_entities); - render_app - .world_mut() - .add_observer(remove_light_view_entities); - render_app.world_mut().add_observer(extracted_light_removed); - - let early_shadow_pass_node = EarlyShadowPassNode::from_world(render_app.world_mut()); - let late_shadow_pass_node = LateShadowPassNode::from_world(render_app.world_mut()); - let mut graph = render_app.world_mut().resource_mut::(); - let draw_3d_graph = graph.get_sub_graph_mut(Core3d).unwrap(); - draw_3d_graph.add_node(NodePbr::EarlyShadowPass, early_shadow_pass_node); - draw_3d_graph.add_node(NodePbr::LateShadowPass, late_shadow_pass_node); - draw_3d_graph.add_node_edges(( - NodePbr::EarlyShadowPass, - NodePbr::LateShadowPass, - Node3d::StartMainPass, - )); - } - - fn finish(&self, app: &mut App) { - let Some(render_app) = app.get_sub_app_mut(RenderApp) else { - return; - }; - - // Extract the required data from the main world - render_app - .init_resource::() - .init_resource::() - .init_resource::(); - } -} - -/// Camera projection PBR functionality. -#[derive(Default)] -pub struct PbrProjectionPlugin; -impl Plugin for PbrProjectionPlugin { - fn build(&self, app: &mut App) { - app.add_systems( - PostUpdate, - build_directional_light_cascades - .in_set(SimulationLightSystems::UpdateDirectionalLightCascades) - .after(clear_directional_light_cascades), - ); } } diff --git a/crates/bevy_pbr/src/pbr_material.rs b/crates/bevy_pbr/src/pbr_material.rs index 4989c2536bf9d..929b12ebca460 100644 --- a/crates/bevy_pbr/src/pbr_material.rs +++ b/crates/bevy_pbr/src/pbr_material.rs @@ -1,14 +1,20 @@ -use bevy_asset::Asset; -use bevy_color::{Alpha, ColorToComponents}; +use bevy_asset::{Asset, Handle}; +use bevy_color::{Alpha, Color, ColorToComponents, LinearRgba}; +use bevy_image::Image; use bevy_math::{Affine2, Affine3, Mat2, Mat3, Vec2, Vec3, Vec4}; use bevy_reflect::{std_traits::ReflectDefault, Reflect}; use bevy_render::{ - mesh::MeshVertexBufferLayoutRef, render_asset::RenderAssets, render_resource::*, - texture::GpuImage, + alpha::AlphaMode, mesh::MeshVertexBufferLayoutRef, render_asset::RenderAssets, + render_resource::*, texture::GpuImage, }; +use bevy_render_3d::{ + deferred::DEFAULT_PBR_DEFERRED_LIGHTING_PASS_ID, Material, MaterialPipeline, + MaterialPipelineKey, OpaqueRendererMethod, +}; + use bitflags::bitflags; -use crate::{deferred::DEFAULT_PBR_DEFERRED_LIGHTING_PASS_ID, *}; +use crate::{prelude::ParallaxMappingMethod, PBR_PREPASS_SHADER_HANDLE, PBR_SHADER_HANDLE}; /// An enum to define which UV attribute to use for a texture. /// @@ -29,6 +35,8 @@ pub enum UvChannel { /// . /// /// May be created directly from a [`Color`] or an [`Image`]. +/// +/// [`StandardMaterial`] comes with out of the box support for forward decals. #[derive(Asset, AsBindGroup, Reflect, Debug, Clone)] #[bind_group_data(StandardMaterialKey)] #[data(0, StandardMaterialUniform, binding_array(10))] @@ -215,7 +223,7 @@ pub struct StandardMaterial { /// /// - The material's [`StandardMaterial::base_color`] also modulates the transmitted light; /// - To receive transmitted shadows on the diffuse transmission lobe (i.e. the “backside”) of the material, - /// use the [`TransmittedShadowReceiver`] component. + /// use the [`TransmittedShadowReceiver`](bevy_render_3d::TransmittedShadowReceiver) component. #[doc(alias = "translucency")] pub diffuse_transmission: f32, diff --git a/crates/bevy_pbr/src/wireframe.rs b/crates/bevy_pbr/src/wireframe.rs index 88082c2880546..9364dc8157288 100644 --- a/crates/bevy_pbr/src/wireframe.rs +++ b/crates/bevy_pbr/src/wireframe.rs @@ -1,14 +1,28 @@ -use crate::{Material, MaterialPipeline, MaterialPipelineKey, MaterialPlugin, MeshMaterial3d}; use bevy_app::{Plugin, Startup, Update}; use bevy_asset::{load_internal_asset, weak_handle, Asset, AssetApp, Assets, Handle}; use bevy_color::{Color, LinearRgba}; -use bevy_ecs::prelude::*; +use bevy_ecs::{ + component::Component, + entity::Entity, + prelude::resource_changed, + query::{Changed, With, Without}, + reflect::{ReflectComponent, ReflectResource}, + removal_detection::RemovedComponents, + resource::Resource, + schedule::IntoScheduleConfigs, + system::{Commands, Query, Res, ResMut}, +}; use bevy_reflect::{std_traits::ReflectDefault, Reflect}; use bevy_render::{ extract_resource::ExtractResource, mesh::{Mesh3d, MeshVertexBufferLayoutRef}, - prelude::*, - render_resource::*, + render_resource::{ + AsBindGroup, PolygonMode, RenderPipelineDescriptor, Shader, ShaderRef, + SpecializedMeshPipelineError, + }, +}; +use bevy_render_3d::{ + Material, MaterialPipeline, MaterialPipelineKey, MaterialPlugin, MeshMaterial3d, }; pub const WIREFRAME_SHADER_HANDLE: Handle = diff --git a/crates/bevy_render_3d/Cargo.toml b/crates/bevy_render_3d/Cargo.toml new file mode 100644 index 0000000000000..4ee0577e93406 --- /dev/null +++ b/crates/bevy_render_3d/Cargo.toml @@ -0,0 +1,82 @@ +[package] +name = "bevy_render_3d" +version = "0.16.0-dev" +edition = "2024" +description = "Provides functionality for rendering in 3d" +homepage = "https://bevyengine.org" +repository = "https://github.com/bevyengine/bevy" +license = "MIT OR Apache-2.0" +keywords = ["bevy"] + +[features] +webgl = [] +webgpu = [] +pbr_transmission_textures = [] +pbr_multi_layer_material_textures = [] +pbr_anisotropy_texture = [] +experimental_pbr_pcss = [] +pbr_specular_textures = [] +shader_format_glsl = ["bevy_render/shader_format_glsl"] +trace = ["bevy_render/trace"] +# Enables the meshlet renderer for dense high-poly scenes (experimental) +meshlet = ["dep:lz4_flex", "dep:range-alloc", "dep:half", "dep:bevy_tasks"] +# Enables processing meshes into meshlet meshes +meshlet_processor = [ + "meshlet", + "dep:meshopt", + "dep:metis", + "dep:itertools", + "dep:bitvec", +] + +[dependencies] +# bevy +bevy_app = { path = "../bevy_app", version = "0.16.0-dev" } +bevy_asset = { path = "../bevy_asset", version = "0.16.0-dev" } +bevy_color = { path = "../bevy_color", version = "0.16.0-dev" } +bevy_core_pipeline = { path = "../bevy_core_pipeline", version = "0.16.0-dev" } +bevy_derive = { path = "../bevy_derive", version = "0.16.0-dev" } +bevy_diagnostic = { path = "../bevy_diagnostic", version = "0.16.0-dev" } +bevy_ecs = { path = "../bevy_ecs", version = "0.16.0-dev" } +bevy_image = { path = "../bevy_image", version = "0.16.0-dev" } +bevy_math = { path = "../bevy_math", version = "0.16.0-dev" } +bevy_platform_support = { path = "../bevy_platform_support", version = "0.16.0-dev", default-features = false, features = [ + "std", +] } +bevy_reflect = { path = "../bevy_reflect", version = "0.16.0-dev" } +bevy_render = { path = "../bevy_render", version = "0.16.0-dev" } +bevy_tasks = { path = "../bevy_tasks", version = "0.16.0-dev", optional = true } +bevy_transform = { path = "../bevy_transform", version = "0.16.0-dev" } +bevy_utils = { path = "../bevy_utils", version = "0.16.0-dev" } +bevy_window = { path = "../bevy_window", version = "0.16.0-dev" } + +# other +bitflags = "2.3" +derive_more = { version = "1", default-features = false, features = ["from"] } +fixedbitset = "0.5" +thiserror = { version = "2", default-features = false } +# meshlet +lz4_flex = { version = "0.11", default-features = false, features = [ + "frame", +], optional = true } +range-alloc = { version = "0.1.3", optional = true } +half = { version = "2", features = ["bytemuck"], optional = true } +meshopt = { version = "0.4.1", optional = true } +metis = { version = "0.2", optional = true } +itertools = { version = "0.14", optional = true } +bitvec = { version = "1", optional = true } +# direct dependency required for derive macro +bytemuck = { version = "1", features = ["derive", "must_cast"] } +radsort = "0.1" +smallvec = "1.6" +nonmax = "0.5" +static_assertions = "1" +tracing = { version = "0.1", default-features = false, features = ["std"] } +offset-allocator = "0.2" + +[lints] +workspace = true + +[package.metadata.docs.rs] +rustdoc-args = ["-Zunstable-options", "--generate-link-to-definition"] +all-features = true diff --git a/crates/bevy_render_3d/LICENSE-APACHE b/crates/bevy_render_3d/LICENSE-APACHE new file mode 100644 index 0000000000000..d9a10c0d8e868 --- /dev/null +++ b/crates/bevy_render_3d/LICENSE-APACHE @@ -0,0 +1,176 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS diff --git a/crates/bevy_render_3d/LICENSE-MIT b/crates/bevy_render_3d/LICENSE-MIT new file mode 100644 index 0000000000000..9cf106272ac3b --- /dev/null +++ b/crates/bevy_render_3d/LICENSE-MIT @@ -0,0 +1,19 @@ +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/crates/bevy_render_3d/README.md b/crates/bevy_render_3d/README.md new file mode 100644 index 0000000000000..d9c1eafa8778f --- /dev/null +++ b/crates/bevy_render_3d/README.md @@ -0,0 +1,7 @@ +# Bevy Render 3d + +[![License](https://img.shields.io/badge/license-MIT%2FApache-blue.svg)](https://github.com/bevyengine/bevy#license) +[![Crates.io](https://img.shields.io/crates/v/bevy_pbr.svg)](https://crates.io/crates/bevy_pbr) +[![Downloads](https://img.shields.io/crates/d/bevy_pbr.svg)](https://crates.io/crates/bevy_pbr) +[![Docs](https://docs.rs/bevy_pbr/badge.svg)](https://docs.rs/bevy_pbr/latest/bevy_pbr/) +[![Discord](https://img.shields.io/discord/691052431525675048.svg?label=&logo=discord&logoColor=ffffff&color=7389D8&labelColor=6A7EC2)](https://discord.gg/bevy) diff --git a/crates/bevy_pbr/src/atmosphere/aerial_view_lut.wgsl b/crates/bevy_render_3d/src/atmosphere/aerial_view_lut.wgsl similarity index 100% rename from crates/bevy_pbr/src/atmosphere/aerial_view_lut.wgsl rename to crates/bevy_render_3d/src/atmosphere/aerial_view_lut.wgsl diff --git a/crates/bevy_pbr/src/atmosphere/bindings.wgsl b/crates/bevy_render_3d/src/atmosphere/bindings.wgsl similarity index 100% rename from crates/bevy_pbr/src/atmosphere/bindings.wgsl rename to crates/bevy_render_3d/src/atmosphere/bindings.wgsl diff --git a/crates/bevy_pbr/src/atmosphere/bruneton_functions.wgsl b/crates/bevy_render_3d/src/atmosphere/bruneton_functions.wgsl similarity index 100% rename from crates/bevy_pbr/src/atmosphere/bruneton_functions.wgsl rename to crates/bevy_render_3d/src/atmosphere/bruneton_functions.wgsl diff --git a/crates/bevy_pbr/src/atmosphere/functions.wgsl b/crates/bevy_render_3d/src/atmosphere/functions.wgsl similarity index 100% rename from crates/bevy_pbr/src/atmosphere/functions.wgsl rename to crates/bevy_render_3d/src/atmosphere/functions.wgsl diff --git a/crates/bevy_pbr/src/atmosphere/mod.rs b/crates/bevy_render_3d/src/atmosphere/mod.rs similarity index 100% rename from crates/bevy_pbr/src/atmosphere/mod.rs rename to crates/bevy_render_3d/src/atmosphere/mod.rs diff --git a/crates/bevy_pbr/src/atmosphere/multiscattering_lut.wgsl b/crates/bevy_render_3d/src/atmosphere/multiscattering_lut.wgsl similarity index 100% rename from crates/bevy_pbr/src/atmosphere/multiscattering_lut.wgsl rename to crates/bevy_render_3d/src/atmosphere/multiscattering_lut.wgsl diff --git a/crates/bevy_pbr/src/atmosphere/node.rs b/crates/bevy_render_3d/src/atmosphere/node.rs similarity index 100% rename from crates/bevy_pbr/src/atmosphere/node.rs rename to crates/bevy_render_3d/src/atmosphere/node.rs diff --git a/crates/bevy_pbr/src/atmosphere/render_sky.wgsl b/crates/bevy_render_3d/src/atmosphere/render_sky.wgsl similarity index 100% rename from crates/bevy_pbr/src/atmosphere/render_sky.wgsl rename to crates/bevy_render_3d/src/atmosphere/render_sky.wgsl diff --git a/crates/bevy_pbr/src/atmosphere/resources.rs b/crates/bevy_render_3d/src/atmosphere/resources.rs similarity index 100% rename from crates/bevy_pbr/src/atmosphere/resources.rs rename to crates/bevy_render_3d/src/atmosphere/resources.rs diff --git a/crates/bevy_pbr/src/atmosphere/sky_view_lut.wgsl b/crates/bevy_render_3d/src/atmosphere/sky_view_lut.wgsl similarity index 100% rename from crates/bevy_pbr/src/atmosphere/sky_view_lut.wgsl rename to crates/bevy_render_3d/src/atmosphere/sky_view_lut.wgsl diff --git a/crates/bevy_pbr/src/atmosphere/transmittance_lut.wgsl b/crates/bevy_render_3d/src/atmosphere/transmittance_lut.wgsl similarity index 100% rename from crates/bevy_pbr/src/atmosphere/transmittance_lut.wgsl rename to crates/bevy_render_3d/src/atmosphere/transmittance_lut.wgsl diff --git a/crates/bevy_pbr/src/atmosphere/types.wgsl b/crates/bevy_render_3d/src/atmosphere/types.wgsl similarity index 100% rename from crates/bevy_pbr/src/atmosphere/types.wgsl rename to crates/bevy_render_3d/src/atmosphere/types.wgsl diff --git a/crates/bevy_pbr/src/cluster/assign.rs b/crates/bevy_render_3d/src/cluster/assign.rs similarity index 100% rename from crates/bevy_pbr/src/cluster/assign.rs rename to crates/bevy_render_3d/src/cluster/assign.rs diff --git a/crates/bevy_pbr/src/cluster/mod.rs b/crates/bevy_render_3d/src/cluster/mod.rs similarity index 100% rename from crates/bevy_pbr/src/cluster/mod.rs rename to crates/bevy_render_3d/src/cluster/mod.rs diff --git a/crates/bevy_pbr/src/cluster/test.rs b/crates/bevy_render_3d/src/cluster/test.rs similarity index 100% rename from crates/bevy_pbr/src/cluster/test.rs rename to crates/bevy_render_3d/src/cluster/test.rs diff --git a/crates/bevy_pbr/src/components.rs b/crates/bevy_render_3d/src/components.rs similarity index 100% rename from crates/bevy_pbr/src/components.rs rename to crates/bevy_render_3d/src/components.rs diff --git a/crates/bevy_pbr/src/decal/clustered.rs b/crates/bevy_render_3d/src/decal/clustered.rs similarity index 100% rename from crates/bevy_pbr/src/decal/clustered.rs rename to crates/bevy_render_3d/src/decal/clustered.rs diff --git a/crates/bevy_pbr/src/decal/clustered.wgsl b/crates/bevy_render_3d/src/decal/clustered.wgsl similarity index 100% rename from crates/bevy_pbr/src/decal/clustered.wgsl rename to crates/bevy_render_3d/src/decal/clustered.wgsl diff --git a/crates/bevy_pbr/src/decal/forward.rs b/crates/bevy_render_3d/src/decal/forward.rs similarity index 91% rename from crates/bevy_pbr/src/decal/forward.rs rename to crates/bevy_render_3d/src/decal/forward.rs index 862d4b6019d08..5eb91006e3559 100644 --- a/crates/bevy_pbr/src/decal/forward.rs +++ b/crates/bevy_render_3d/src/decal/forward.rs @@ -1,6 +1,8 @@ +use core::marker::PhantomData; + use crate::{ ExtendedMaterial, Material, MaterialExtension, MaterialExtensionKey, MaterialExtensionPipeline, - MaterialPlugin, StandardMaterial, + MaterialPlugin, }; use bevy_app::{App, Plugin}; use bevy_asset::{load_internal_asset, weak_handle, Asset, Assets, Handle}; @@ -23,9 +25,18 @@ const FORWARD_DECAL_SHADER_HANDLE: Handle = weak_handle!("f8dfbef4-d88b-42ae-9af4-d9661e9f1648"); /// Plugin to render [`ForwardDecal`]s. -pub struct ForwardDecalPlugin; +pub struct ForwardDecalPlugin(PhantomData); + +impl Default for ForwardDecalPlugin { + fn default() -> Self { + Self(PhantomData) + } +} -impl Plugin for ForwardDecalPlugin { +impl Plugin for ForwardDecalPlugin +where + MaterialPlugin>: Plugin, +{ fn build(&self, app: &mut App) { load_internal_asset!( app, @@ -46,7 +57,7 @@ impl Plugin for ForwardDecalPlugin { .unwrap(), ); - app.add_plugins(MaterialPlugin::> { + app.add_plugins(MaterialPlugin::> { prepass_enabled: false, shadows_enabled: false, debug_flags: RenderDebugFlags::default(), @@ -73,8 +84,6 @@ pub struct ForwardDecal; /// Type alias for an extended material with a [`ForwardDecalMaterialExt`] extension. /// /// Make sure to register the [`MaterialPlugin`] for this material in your app setup. -/// -/// [`StandardMaterial`] comes with out of the box support for forward decals. #[expect(type_alias_bounds, reason = "Type alias generics not yet stable")] pub type ForwardDecalMaterial = ExtendedMaterial; diff --git a/crates/bevy_pbr/src/decal/forward_decal.wgsl b/crates/bevy_render_3d/src/decal/forward_decal.wgsl similarity index 100% rename from crates/bevy_pbr/src/decal/forward_decal.wgsl rename to crates/bevy_render_3d/src/decal/forward_decal.wgsl diff --git a/crates/bevy_pbr/src/decal/mod.rs b/crates/bevy_render_3d/src/decal/mod.rs similarity index 100% rename from crates/bevy_pbr/src/decal/mod.rs rename to crates/bevy_render_3d/src/decal/mod.rs diff --git a/crates/bevy_pbr/src/deferred/deferred_lighting.wgsl b/crates/bevy_render_3d/src/deferred/deferred_lighting.wgsl similarity index 100% rename from crates/bevy_pbr/src/deferred/deferred_lighting.wgsl rename to crates/bevy_render_3d/src/deferred/deferred_lighting.wgsl diff --git a/crates/bevy_pbr/src/deferred/mod.rs b/crates/bevy_render_3d/src/deferred/mod.rs similarity index 100% rename from crates/bevy_pbr/src/deferred/mod.rs rename to crates/bevy_render_3d/src/deferred/mod.rs diff --git a/crates/bevy_pbr/src/deferred/pbr_deferred_functions.wgsl b/crates/bevy_render_3d/src/deferred/pbr_deferred_functions.wgsl similarity index 100% rename from crates/bevy_pbr/src/deferred/pbr_deferred_functions.wgsl rename to crates/bevy_render_3d/src/deferred/pbr_deferred_functions.wgsl diff --git a/crates/bevy_pbr/src/deferred/pbr_deferred_types.wgsl b/crates/bevy_render_3d/src/deferred/pbr_deferred_types.wgsl similarity index 100% rename from crates/bevy_pbr/src/deferred/pbr_deferred_types.wgsl rename to crates/bevy_render_3d/src/deferred/pbr_deferred_types.wgsl diff --git a/crates/bevy_pbr/src/extended_material.rs b/crates/bevy_render_3d/src/extended_material.rs similarity index 100% rename from crates/bevy_pbr/src/extended_material.rs rename to crates/bevy_render_3d/src/extended_material.rs diff --git a/crates/bevy_pbr/src/fog.rs b/crates/bevy_render_3d/src/fog.rs similarity index 99% rename from crates/bevy_pbr/src/fog.rs rename to crates/bevy_render_3d/src/fog.rs index 21a89ccc70ab7..50bf74dadbfbf 100644 --- a/crates/bevy_pbr/src/fog.rs +++ b/crates/bevy_render_3d/src/fog.rs @@ -6,7 +6,6 @@ use bevy_render::{extract_component::ExtractComponent, prelude::Camera}; /// Configures the “classic” computer graphics [distance fog](https://en.wikipedia.org/wiki/Distance_fog) effect, /// in which objects appear progressively more covered in atmospheric haze the further away they are from the camera. -/// Affects meshes rendered via the PBR [`StandardMaterial`](crate::StandardMaterial). /// /// ## Falloff /// @@ -23,8 +22,8 @@ use bevy_render::{extract_component::ExtractComponent, prelude::Camera}; /// ``` /// # use bevy_ecs::prelude::*; /// # use bevy_render::prelude::*; +/// # use bevy_render_3d::prelude::*; /// # use bevy_core_pipeline::prelude::*; -/// # use bevy_pbr::prelude::*; /// # use bevy_color::Color; /// # fn system(mut commands: Commands) { /// commands.spawn(( @@ -44,7 +43,7 @@ use bevy_render::{extract_component::ExtractComponent, prelude::Camera}; /// ## Material Override /// /// Once enabled for a specific camera, the fog effect can also be disabled for individual -/// [`StandardMaterial`](crate::StandardMaterial) instances via the `fog_enabled` flag. +/// [`Material`](crate::Material) instances that have fog pipeline enabled. #[derive(Debug, Clone, Component, Reflect, ExtractComponent)] #[extract_component_filter(With)] #[reflect(Component, Default, Debug, Clone)] @@ -261,7 +260,7 @@ pub enum FogFalloff { /// For a density value of `D`, the following two falloff modes will produce identical visual results: /// /// ``` - /// # use bevy_pbr::prelude::*; + /// # use bevy_render_3d::prelude::*; /// # use bevy_math::prelude::*; /// # const D: f32 = 0.5; /// # diff --git a/crates/bevy_render_3d/src/lib.rs b/crates/bevy_render_3d/src/lib.rs new file mode 100644 index 0000000000000..4f7dfec50b9eb --- /dev/null +++ b/crates/bevy_render_3d/src/lib.rs @@ -0,0 +1,422 @@ +#![expect(missing_docs, reason = "Not all docs are written yet, see #3492.")] +#![cfg_attr(docsrs, feature(doc_auto_cfg))] +#![forbid(unsafe_code)] +#![doc( + html_logo_url = "https://bevyengine.org/assets/icon.png", + html_favicon_url = "https://bevyengine.org/assets/icon.png" +)] + +extern crate alloc; + +#[cfg(feature = "meshlet")] +mod meshlet; + +/// Experimental features that are not yet finished. Please report any issues you encounter! +/// +/// Expect bugs, missing features, compatibility issues, low performance, and/or future breaking changes. +#[cfg(feature = "meshlet")] +pub mod experimental { + /// Render high-poly 3d meshes using an efficient GPU-driven method. + /// See [`MeshletPlugin`](meshlet::MeshletPlugin) and [`MeshletMesh`](meshlet::MeshletMesh) for details. + pub mod meshlet { + pub use crate::meshlet::*; + } +} + +mod atmosphere; +mod cluster; +mod components; +pub mod decal; +pub mod deferred; +mod extended_material; +mod fog; +mod light; +mod light_probe; +mod lightmap; +mod material; +mod material_bind_groups; +mod mesh_material; +mod prepass; +mod render; +mod ssao; +mod ssr; +mod volumetric_fog; + +use bevy_color::{Color, LinearRgba}; + +pub use atmosphere::*; +pub use cluster::*; +pub use components::*; +pub use decal::clustered::ClusteredDecalPlugin; +pub use extended_material::*; +pub use fog::*; +pub use light::*; +pub use light_probe::*; +pub use lightmap::*; +pub use material::*; +pub use material_bind_groups::*; +pub use mesh_material::*; +pub use prepass::*; +pub use render::*; +pub use ssao::*; +pub use ssr::*; +pub use volumetric_fog::{FogVolume, VolumetricFog, VolumetricFogPlugin, VolumetricLight}; + +/// The PBR prelude. +/// +/// This includes the most common types in this crate, re-exported for your convenience. +pub mod prelude { + #[doc(hidden)] + pub use crate::{ + fog::{DistanceFog, FogFalloff}, + light::{light_consts, AmbientLight, DirectionalLight, PointLight, SpotLight}, + light_probe::{environment_map::EnvironmentMapLight, LightProbe}, + material::{Material, MaterialPlugin}, + mesh_material::MeshMaterial3d, + ssao::ScreenSpaceAmbientOcclusionPlugin, + }; +} + +pub mod graph { + use bevy_render::render_graph::RenderLabel; + + /// Render graph nodes specific to 3D PBR rendering. + #[derive(Debug, Hash, PartialEq, Eq, Clone, RenderLabel)] + pub enum NodePbr { + /// Label for the shadow pass node that draws meshes that were visible + /// from the light last frame. + EarlyShadowPass, + /// Label for the shadow pass node that draws meshes that became visible + /// from the light this frame. + LateShadowPass, + /// Label for the screen space ambient occlusion render node. + ScreenSpaceAmbientOcclusion, + DeferredLightingPass, + /// Label for the volumetric lighting pass. + VolumetricFog, + /// Label for the shader that transforms and culls meshes that were + /// visible last frame. + EarlyGpuPreprocess, + /// Label for the shader that transforms and culls meshes that became + /// visible this frame. + LateGpuPreprocess, + /// Label for the screen space reflections pass. + ScreenSpaceReflections, + /// Label for the node that builds indirect draw parameters for meshes + /// that were visible last frame. + EarlyPrepassBuildIndirectParameters, + /// Label for the node that builds indirect draw parameters for meshes + /// that became visible this frame. + LatePrepassBuildIndirectParameters, + /// Label for the node that builds indirect draw parameters for the main + /// rendering pass, containing all meshes that are visible this frame. + MainBuildIndirectParameters, + ClearIndirectParametersMetadata, + } +} + +use bevy_app::prelude::*; +use bevy_asset::{load_internal_asset, weak_handle, AssetApp, Handle}; +use bevy_core_pipeline::core_3d::graph::{Core3d, Node3d}; +use bevy_ecs::prelude::*; +use bevy_image::Image; +use bevy_render::{ + alpha::AlphaMode, + camera::{sort_cameras, CameraUpdateSystem, Projection}, + extract_component::ExtractComponentPlugin, + extract_resource::ExtractResourcePlugin, + render_graph::RenderGraph, + render_resource::Shader, + sync_component::SyncComponentPlugin, + view::VisibilitySystems, + ExtractSchedule, Render, RenderApp, RenderDebugFlags, RenderSet, +}; +use bevy_transform::TransformSystem; + +use crate::{deferred::DeferredPbrLightingPlugin, graph::NodePbr}; + +const UTILS_HANDLE: Handle = weak_handle!("0a32978f-2744-4608-98b6-4c3000a0638d"); +const CLUSTERED_FORWARD_HANDLE: Handle = + weak_handle!("f8e3b4c6-60b7-4b23-8b2e-a6b27bb4ddce"); +const PBR_LIGHTING_HANDLE: Handle = weak_handle!("de0cf697-2876-49a0-aa0f-f015216f70c2"); +const PBR_TRANSMISSION_HANDLE: Handle = + weak_handle!("22482185-36bb-4c16-9b93-a20e6d4a2725"); +const SHADOWS_HANDLE: Handle = weak_handle!("ff758c5a-3927-4a15-94c3-3fbdfc362590"); +const SHADOW_SAMPLING_HANDLE: Handle = weak_handle!("f6bf5843-54bc-4e39-bd9d-56bfcd77b033"); +const VIEW_TRANSFORMATIONS_SHADER_HANDLE: Handle = + weak_handle!("ec047703-cde3-4876-94df-fed121544abb"); +const PBR_DEFERRED_TYPES_HANDLE: Handle = + weak_handle!("43060da7-a717-4240-80a8-dbddd92bd25d"); +const PBR_DEFERRED_FUNCTIONS_HANDLE: Handle = + weak_handle!("9dc46746-c51d-45e3-a321-6a50c3963420"); +const MESHLET_VISIBILITY_BUFFER_RESOLVE_SHADER_HANDLE: Handle = + weak_handle!("69187376-3dea-4d0f-b3f5-185bde63d6a2"); + +const TONEMAPPING_LUT_TEXTURE_BINDING_INDEX: u32 = 26; +const TONEMAPPING_LUT_SAMPLER_BINDING_INDEX: u32 = 27; + +/// Sets up the entire 3d rendering infrastructure of bevy. +pub struct MeshPipelinePlugin { + /// Controls if [`DeferredPbrLightingPlugin`] is added. + pub add_default_deferred_lighting_plugin: bool, + /// Controls if GPU [`MeshUniform`] building is enabled. + /// + /// This requires compute shader support and so will be forcibly disabled if + /// the platform doesn't support those. + pub use_gpu_instance_buffer_builder: bool, + /// Debugging flags that can optionally be set when constructing the renderer. + pub debug_flags: RenderDebugFlags, +} + +impl Default for MeshPipelinePlugin { + fn default() -> Self { + Self { + add_default_deferred_lighting_plugin: true, + use_gpu_instance_buffer_builder: true, + debug_flags: RenderDebugFlags::default(), + } + } +} + +impl Plugin for MeshPipelinePlugin { + fn build(&self, app: &mut App) { + load_internal_asset!(app, UTILS_HANDLE, "render/utils.wgsl", Shader::from_wgsl); + load_internal_asset!( + app, + CLUSTERED_FORWARD_HANDLE, + "render/clustered_forward.wgsl", + Shader::from_wgsl + ); + load_internal_asset!( + app, + PBR_LIGHTING_HANDLE, + "render/pbr_lighting.wgsl", + Shader::from_wgsl + ); + load_internal_asset!( + app, + PBR_TRANSMISSION_HANDLE, + "render/pbr_transmission.wgsl", + Shader::from_wgsl + ); + load_internal_asset!( + app, + SHADOWS_HANDLE, + "render/shadows.wgsl", + Shader::from_wgsl + ); + load_internal_asset!( + app, + PBR_DEFERRED_TYPES_HANDLE, + "deferred/pbr_deferred_types.wgsl", + Shader::from_wgsl + ); + load_internal_asset!( + app, + PBR_DEFERRED_FUNCTIONS_HANDLE, + "deferred/pbr_deferred_functions.wgsl", + Shader::from_wgsl + ); + load_internal_asset!( + app, + SHADOW_SAMPLING_HANDLE, + "render/shadow_sampling.wgsl", + Shader::from_wgsl + ); + load_internal_asset!( + app, + VIEW_TRANSFORMATIONS_SHADER_HANDLE, + "render/view_transformations.wgsl", + Shader::from_wgsl + ); + // Setup dummy shaders for when MeshletPlugin is not used to prevent shader import errors. + load_internal_asset!( + app, + MESHLET_VISIBILITY_BUFFER_RESOLVE_SHADER_HANDLE, + "meshlet/dummy_visibility_buffer_resolve.wgsl", + Shader::from_wgsl + ); + + app.register_type::() + .register_type::() + .register_type::() + .register_type::() + .register_type::() + .register_type::() + .register_type::() + .register_type::() + .register_type::() + .register_type::() + .register_type::() + .register_type::() + .register_type::() + .register_type::() + .register_type::() + .init_resource::() + .init_resource::() + .init_resource::() + .init_resource::() + .register_type::() + .init_resource::() + .add_plugins(( + MeshRenderPlugin { + use_gpu_instance_buffer_builder: self.use_gpu_instance_buffer_builder, + debug_flags: self.debug_flags, + }, + ScreenSpaceAmbientOcclusionPlugin, + ExtractResourcePlugin::::default(), + FogPlugin, + ExtractResourcePlugin::::default(), + ExtractComponentPlugin::::default(), + LightmapPlugin, + LightProbePlugin, + PbrProjectionPlugin, + GpuMeshPreprocessPlugin { + use_gpu_instance_buffer_builder: self.use_gpu_instance_buffer_builder, + }, + VolumetricFogPlugin, + ScreenSpaceReflectionsPlugin, + ClusteredDecalPlugin, + )) + .add_plugins(( + SyncComponentPlugin::::default(), + SyncComponentPlugin::::default(), + SyncComponentPlugin::::default(), + ExtractComponentPlugin::::default(), + )) + .add_plugins(AtmospherePlugin) + .configure_sets( + PostUpdate, + ( + SimulationLightSystems::AddClusters, + SimulationLightSystems::AssignLightsToClusters, + ) + .chain(), + ) + .configure_sets( + PostUpdate, + SimulationLightSystems::UpdateDirectionalLightCascades + .ambiguous_with(SimulationLightSystems::UpdateDirectionalLightCascades), + ) + .configure_sets( + PostUpdate, + SimulationLightSystems::CheckLightVisibility + .ambiguous_with(SimulationLightSystems::CheckLightVisibility), + ) + .add_systems( + PostUpdate, + ( + add_clusters + .in_set(SimulationLightSystems::AddClusters) + .after(CameraUpdateSystem), + assign_objects_to_clusters + .in_set(SimulationLightSystems::AssignLightsToClusters) + .after(TransformSystem::TransformPropagate) + .after(VisibilitySystems::CheckVisibility) + .after(CameraUpdateSystem), + clear_directional_light_cascades + .in_set(SimulationLightSystems::UpdateDirectionalLightCascades) + .after(TransformSystem::TransformPropagate) + .after(CameraUpdateSystem), + update_directional_light_frusta + .in_set(SimulationLightSystems::UpdateLightFrusta) + // This must run after CheckVisibility because it relies on `ViewVisibility` + .after(VisibilitySystems::CheckVisibility) + .after(TransformSystem::TransformPropagate) + .after(SimulationLightSystems::UpdateDirectionalLightCascades) + // We assume that no entity will be both a directional light and a spot light, + // so these systems will run independently of one another. + // FIXME: Add an archetype invariant for this https://github.com/bevyengine/bevy/issues/1481. + .ambiguous_with(update_spot_light_frusta), + update_point_light_frusta + .in_set(SimulationLightSystems::UpdateLightFrusta) + .after(TransformSystem::TransformPropagate) + .after(SimulationLightSystems::AssignLightsToClusters), + update_spot_light_frusta + .in_set(SimulationLightSystems::UpdateLightFrusta) + .after(TransformSystem::TransformPropagate) + .after(SimulationLightSystems::AssignLightsToClusters), + ( + check_dir_light_mesh_visibility, + check_point_light_mesh_visibility, + ) + .in_set(SimulationLightSystems::CheckLightVisibility) + .after(VisibilitySystems::CalculateBounds) + .after(TransformSystem::TransformPropagate) + .after(SimulationLightSystems::UpdateLightFrusta) + // NOTE: This MUST be scheduled AFTER the core renderer visibility check + // because that resets entity `ViewVisibility` for the first view + // which would override any results from this otherwise + .after(VisibilitySystems::CheckVisibility) + .before(VisibilitySystems::MarkNewlyHiddenEntitiesInvisible), + ), + ); + + if self.add_default_deferred_lighting_plugin { + app.add_plugins(DeferredPbrLightingPlugin); + } + + let Some(render_app) = app.get_sub_app_mut(RenderApp) else { + return; + }; + + // Extract the required data from the main world + render_app + .add_systems(ExtractSchedule, (extract_clusters, extract_lights)) + .add_systems( + Render, + ( + prepare_lights + .in_set(RenderSet::ManageViews) + .after(sort_cameras), + prepare_clusters.in_set(RenderSet::PrepareResources), + ), + ) + .init_resource::() + .init_resource::(); + + render_app.world_mut().add_observer(add_light_view_entities); + render_app + .world_mut() + .add_observer(remove_light_view_entities); + render_app.world_mut().add_observer(extracted_light_removed); + + let early_shadow_pass_node = EarlyShadowPassNode::from_world(render_app.world_mut()); + let late_shadow_pass_node = LateShadowPassNode::from_world(render_app.world_mut()); + let mut graph = render_app.world_mut().resource_mut::(); + let draw_3d_graph = graph.get_sub_graph_mut(Core3d).unwrap(); + draw_3d_graph.add_node(NodePbr::EarlyShadowPass, early_shadow_pass_node); + draw_3d_graph.add_node(NodePbr::LateShadowPass, late_shadow_pass_node); + draw_3d_graph.add_node_edges(( + NodePbr::EarlyShadowPass, + NodePbr::LateShadowPass, + Node3d::StartMainPass, + )); + } + + fn finish(&self, app: &mut App) { + let Some(render_app) = app.get_sub_app_mut(RenderApp) else { + return; + }; + + // Extract the required data from the main world + render_app + .init_resource::() + .init_resource::() + .init_resource::(); + } +} + +/// Camera projection PBR functionality. +#[derive(Default)] +pub struct PbrProjectionPlugin; +impl Plugin for PbrProjectionPlugin { + fn build(&self, app: &mut App) { + app.add_systems( + PostUpdate, + build_directional_light_cascades + .in_set(SimulationLightSystems::UpdateDirectionalLightCascades) + .after(clear_directional_light_cascades), + ); + } +} diff --git a/crates/bevy_pbr/src/light/ambient_light.rs b/crates/bevy_render_3d/src/light/ambient_light.rs similarity index 91% rename from crates/bevy_pbr/src/light/ambient_light.rs rename to crates/bevy_render_3d/src/light/ambient_light.rs index db255722b3aec..1ae4bc9f06c5a 100644 --- a/crates/bevy_pbr/src/light/ambient_light.rs +++ b/crates/bevy_render_3d/src/light/ambient_light.rs @@ -2,7 +2,7 @@ use super::*; /// An ambient light, which lights the entire scene equally. /// -/// This resource is inserted by the [`PbrPlugin`] and by default it is set to a low ambient light. +/// This resource is inserted by the [`MeshPipelinePlugin`] and by default it is set to a low ambient light. /// /// It can also be added to a camera to override the resource (or default) ambient for that camera only. /// @@ -12,7 +12,7 @@ use super::*; /// /// ``` /// # use bevy_ecs::system::ResMut; -/// # use bevy_pbr::AmbientLight; +/// # use bevy_render_3d::AmbientLight; /// fn setup_ambient_light(mut ambient_light: ResMut) { /// ambient_light.brightness = 100.0; /// } diff --git a/crates/bevy_pbr/src/light/directional_light.rs b/crates/bevy_render_3d/src/light/directional_light.rs similarity index 99% rename from crates/bevy_pbr/src/light/directional_light.rs rename to crates/bevy_render_3d/src/light/directional_light.rs index b04a17bf0b66d..97f5b6b9e0f5b 100644 --- a/crates/bevy_pbr/src/light/directional_light.rs +++ b/crates/bevy_render_3d/src/light/directional_light.rs @@ -45,7 +45,7 @@ use super::*; /// /// ``` /// # use bevy_app::prelude::*; -/// # use bevy_pbr::DirectionalLightShadowMap; +/// # use bevy_render_3d::DirectionalLightShadowMap; /// App::new() /// .insert_resource(DirectionalLightShadowMap { size: 2048 }); /// ``` diff --git a/crates/bevy_pbr/src/light/mod.rs b/crates/bevy_render_3d/src/light/mod.rs similarity index 98% rename from crates/bevy_pbr/src/light/mod.rs rename to crates/bevy_render_3d/src/light/mod.rs index cdccfb41211a2..880aeddded86a 100644 --- a/crates/bevy_pbr/src/light/mod.rs +++ b/crates/bevy_render_3d/src/light/mod.rs @@ -124,8 +124,7 @@ impl Default for DirectionalLightShadowMap { /// Prefer using [`CascadeShadowConfigBuilder`] to construct an instance. /// /// ``` -/// # use bevy_pbr::CascadeShadowConfig; -/// # use bevy_pbr::CascadeShadowConfigBuilder; +/// # use bevy_render_3d::{CascadeShadowConfig,CascadeShadowConfigBuilder}; /// # use bevy_utils::default; /// # /// let config: CascadeShadowConfig = CascadeShadowConfigBuilder { @@ -444,10 +443,12 @@ fn calculate_cascade( texel_size: cascade_texel_size, } } + /// Add this component to make a [`Mesh3d`] not cast shadows. #[derive(Debug, Component, Reflect, Default)] #[reflect(Component, Default, Debug)] pub struct NotShadowCaster; + /// Add this component to make a [`Mesh3d`] not receive shadows. /// /// **Note:** If you're using diffuse transmission, setting [`NotShadowReceiver`] will @@ -456,11 +457,8 @@ pub struct NotShadowCaster; #[derive(Debug, Component, Reflect, Default)] #[reflect(Component, Default, Debug)] pub struct NotShadowReceiver; -/// Add this component to make a [`Mesh3d`] using a PBR material with [`diffuse_transmission`](crate::pbr_material::StandardMaterial::diffuse_transmission)`> 0.0` -/// receive shadows on its diffuse transmission lobe. (i.e. its “backside”) -/// -/// Not enabled by default, as it requires carefully setting up [`thickness`](crate::pbr_material::StandardMaterial::thickness) -/// (and potentially even baking a thickness texture!) to match the geometry of the mesh, in order to avoid self-shadow artifacts. + +/// Allow receiving shadows that have been transmitted by transparent objects. /// /// **Note:** Using [`NotShadowReceiver`] overrides this component. #[derive(Debug, Component, Reflect, Default)] diff --git a/crates/bevy_pbr/src/light/point_light.rs b/crates/bevy_render_3d/src/light/point_light.rs similarity index 100% rename from crates/bevy_pbr/src/light/point_light.rs rename to crates/bevy_render_3d/src/light/point_light.rs diff --git a/crates/bevy_pbr/src/light/spot_light.rs b/crates/bevy_render_3d/src/light/spot_light.rs similarity index 100% rename from crates/bevy_pbr/src/light/spot_light.rs rename to crates/bevy_render_3d/src/light/spot_light.rs diff --git a/crates/bevy_pbr/src/light_probe/environment_map.rs b/crates/bevy_render_3d/src/light_probe/environment_map.rs similarity index 100% rename from crates/bevy_pbr/src/light_probe/environment_map.rs rename to crates/bevy_render_3d/src/light_probe/environment_map.rs diff --git a/crates/bevy_pbr/src/light_probe/environment_map.wgsl b/crates/bevy_render_3d/src/light_probe/environment_map.wgsl similarity index 100% rename from crates/bevy_pbr/src/light_probe/environment_map.wgsl rename to crates/bevy_render_3d/src/light_probe/environment_map.wgsl diff --git a/crates/bevy_pbr/src/light_probe/irradiance_volume.rs b/crates/bevy_render_3d/src/light_probe/irradiance_volume.rs similarity index 100% rename from crates/bevy_pbr/src/light_probe/irradiance_volume.rs rename to crates/bevy_render_3d/src/light_probe/irradiance_volume.rs diff --git a/crates/bevy_pbr/src/light_probe/irradiance_volume.wgsl b/crates/bevy_render_3d/src/light_probe/irradiance_volume.wgsl similarity index 100% rename from crates/bevy_pbr/src/light_probe/irradiance_volume.wgsl rename to crates/bevy_render_3d/src/light_probe/irradiance_volume.wgsl diff --git a/crates/bevy_pbr/src/light_probe/light_probe.wgsl b/crates/bevy_render_3d/src/light_probe/light_probe.wgsl similarity index 100% rename from crates/bevy_pbr/src/light_probe/light_probe.wgsl rename to crates/bevy_render_3d/src/light_probe/light_probe.wgsl diff --git a/crates/bevy_pbr/src/light_probe/mod.rs b/crates/bevy_render_3d/src/light_probe/mod.rs similarity index 100% rename from crates/bevy_pbr/src/light_probe/mod.rs rename to crates/bevy_render_3d/src/light_probe/mod.rs diff --git a/crates/bevy_pbr/src/lightmap/lightmap.wgsl b/crates/bevy_render_3d/src/lightmap/lightmap.wgsl similarity index 100% rename from crates/bevy_pbr/src/lightmap/lightmap.wgsl rename to crates/bevy_render_3d/src/lightmap/lightmap.wgsl diff --git a/crates/bevy_pbr/src/lightmap/mod.rs b/crates/bevy_render_3d/src/lightmap/mod.rs similarity index 97% rename from crates/bevy_pbr/src/lightmap/mod.rs rename to crates/bevy_render_3d/src/lightmap/mod.rs index 741085fd9fddf..0b40b01df81be 100644 --- a/crates/bevy_pbr/src/lightmap/mod.rs +++ b/crates/bevy_render_3d/src/lightmap/mod.rs @@ -7,9 +7,7 @@ //! project support other lightmap baking methods. //! //! When a [`Lightmap`] component is added to an entity with a [`Mesh3d`] and a -//! [`MeshMaterial3d`], Bevy applies the lightmap when rendering. The brightness -//! of the lightmap may be controlled with the `lightmap_exposure` field on -//! [`StandardMaterial`]. +//! [`MeshMaterial3d`], Bevy applies the lightmap when rendering. //! //! During the rendering extraction phase, we extract all lightmaps into the //! [`RenderLightmaps`] table, which lives in the render world. Mesh bindgroup @@ -27,8 +25,8 @@ //! //! [The Lightmapper]: https://github.com/Naxela/The_Lightmapper //! [`Mesh3d`]: bevy_render::mesh::Mesh3d -//! [`MeshMaterial3d`]: crate::StandardMaterial -//! [`StandardMaterial`]: crate::StandardMaterial +//! [`MeshMaterial3d`]: crate::MeshMaterial3d +//! [`Material`]: crate::Material //! [`bevy-baked-gi`]: https://github.com/pcwalton/bevy-baked-gi use bevy_app::{App, Plugin}; @@ -84,7 +82,7 @@ pub struct LightmapPlugin; /// lightmap. /// /// When assigned to an entity that contains a [`Mesh3d`](bevy_render::mesh::Mesh3d) and a -/// [`MeshMaterial3d`](crate::StandardMaterial), if the mesh +/// [`MeshMaterial3d`](crate::Material), if the mesh /// has a second UV layer ([`ATTRIBUTE_UV_1`](bevy_render::mesh::Mesh::ATTRIBUTE_UV_1)), /// then the lightmap will render using those UVs. #[derive(Component, Clone, Reflect)] diff --git a/crates/bevy_pbr/src/material.rs b/crates/bevy_render_3d/src/material.rs similarity index 99% rename from crates/bevy_pbr/src/material.rs rename to crates/bevy_render_3d/src/material.rs index 0cf6686b3e9a6..4b82722265a4a 100644 --- a/crates/bevy_pbr/src/material.rs +++ b/crates/bevy_render_3d/src/material.rs @@ -67,11 +67,11 @@ use tracing::error; /// check out the [`AsBindGroup`] documentation. /// /// ``` -/// # use bevy_pbr::{Material, MeshMaterial3d}; /// # use bevy_ecs::prelude::*; /// # use bevy_image::Image; /// # use bevy_reflect::TypePath; /// # use bevy_render::{mesh::{Mesh, Mesh3d}, render_resource::{AsBindGroup, ShaderRef}}; +/// # use bevy_render_3d::{Material, MeshMaterial3d}; /// # use bevy_color::LinearRgba; /// # use bevy_color::palettes::basic::RED; /// # use bevy_asset::{Handle, AssetServer, Assets, Asset}; diff --git a/crates/bevy_pbr/src/material_bind_groups.rs b/crates/bevy_render_3d/src/material_bind_groups.rs similarity index 100% rename from crates/bevy_pbr/src/material_bind_groups.rs rename to crates/bevy_render_3d/src/material_bind_groups.rs diff --git a/crates/bevy_pbr/src/mesh_material.rs b/crates/bevy_render_3d/src/mesh_material.rs similarity index 83% rename from crates/bevy_pbr/src/mesh_material.rs rename to crates/bevy_render_3d/src/mesh_material.rs index 027f2073ec179..1461052441ec1 100644 --- a/crates/bevy_pbr/src/mesh_material.rs +++ b/crates/bevy_render_3d/src/mesh_material.rs @@ -14,25 +14,21 @@ use derive_more::derive::From; /// # Example /// /// ``` -/// # use bevy_pbr::{Material, MeshMaterial3d, StandardMaterial}; /// # use bevy_ecs::prelude::*; /// # use bevy_render::mesh::{Mesh, Mesh3d}; +/// # use bevy_render_3d::{Material, MeshMaterial3d}; /// # use bevy_color::palettes::basic::RED; /// # use bevy_asset::Assets; /// # use bevy_math::primitives::Capsule3d; -/// # -/// // Spawn an entity with a mesh using `StandardMaterial`. -/// fn setup( +/// // Spawn an entity with a mesh with a [`MeshMaterial3d`]. +/// fn setup( /// mut commands: Commands, /// mut meshes: ResMut>, -/// mut materials: ResMut>, +/// mut materials: ResMut> /// ) { /// commands.spawn(( /// Mesh3d(meshes.add(Capsule3d::default())), -/// MeshMaterial3d(materials.add(StandardMaterial { -/// base_color: RED.into(), -/// ..Default::default() -/// })), +/// MeshMaterial3d(materials.add(M::default())), /// )); /// } /// ``` diff --git a/crates/bevy_pbr/src/meshlet/asset.rs b/crates/bevy_render_3d/src/meshlet/asset.rs similarity index 100% rename from crates/bevy_pbr/src/meshlet/asset.rs rename to crates/bevy_render_3d/src/meshlet/asset.rs diff --git a/crates/bevy_pbr/src/meshlet/clear_visibility_buffer.wgsl b/crates/bevy_render_3d/src/meshlet/clear_visibility_buffer.wgsl similarity index 100% rename from crates/bevy_pbr/src/meshlet/clear_visibility_buffer.wgsl rename to crates/bevy_render_3d/src/meshlet/clear_visibility_buffer.wgsl diff --git a/crates/bevy_pbr/src/meshlet/cull_clusters.wgsl b/crates/bevy_render_3d/src/meshlet/cull_clusters.wgsl similarity index 100% rename from crates/bevy_pbr/src/meshlet/cull_clusters.wgsl rename to crates/bevy_render_3d/src/meshlet/cull_clusters.wgsl diff --git a/crates/bevy_pbr/src/meshlet/dummy_visibility_buffer_resolve.wgsl b/crates/bevy_render_3d/src/meshlet/dummy_visibility_buffer_resolve.wgsl similarity index 100% rename from crates/bevy_pbr/src/meshlet/dummy_visibility_buffer_resolve.wgsl rename to crates/bevy_render_3d/src/meshlet/dummy_visibility_buffer_resolve.wgsl diff --git a/crates/bevy_pbr/src/meshlet/fill_cluster_buffers.wgsl b/crates/bevy_render_3d/src/meshlet/fill_cluster_buffers.wgsl similarity index 100% rename from crates/bevy_pbr/src/meshlet/fill_cluster_buffers.wgsl rename to crates/bevy_render_3d/src/meshlet/fill_cluster_buffers.wgsl diff --git a/crates/bevy_pbr/src/meshlet/from_mesh.rs b/crates/bevy_render_3d/src/meshlet/from_mesh.rs similarity index 100% rename from crates/bevy_pbr/src/meshlet/from_mesh.rs rename to crates/bevy_render_3d/src/meshlet/from_mesh.rs diff --git a/crates/bevy_pbr/src/meshlet/instance_manager.rs b/crates/bevy_render_3d/src/meshlet/instance_manager.rs similarity index 100% rename from crates/bevy_pbr/src/meshlet/instance_manager.rs rename to crates/bevy_render_3d/src/meshlet/instance_manager.rs diff --git a/crates/bevy_pbr/src/meshlet/material_pipeline_prepare.rs b/crates/bevy_render_3d/src/meshlet/material_pipeline_prepare.rs similarity index 100% rename from crates/bevy_pbr/src/meshlet/material_pipeline_prepare.rs rename to crates/bevy_render_3d/src/meshlet/material_pipeline_prepare.rs diff --git a/crates/bevy_pbr/src/meshlet/material_shade_nodes.rs b/crates/bevy_render_3d/src/meshlet/material_shade_nodes.rs similarity index 100% rename from crates/bevy_pbr/src/meshlet/material_shade_nodes.rs rename to crates/bevy_render_3d/src/meshlet/material_shade_nodes.rs diff --git a/crates/bevy_pbr/src/meshlet/meshlet_bindings.wgsl b/crates/bevy_render_3d/src/meshlet/meshlet_bindings.wgsl similarity index 100% rename from crates/bevy_pbr/src/meshlet/meshlet_bindings.wgsl rename to crates/bevy_render_3d/src/meshlet/meshlet_bindings.wgsl diff --git a/crates/bevy_pbr/src/meshlet/meshlet_mesh_manager.rs b/crates/bevy_render_3d/src/meshlet/meshlet_mesh_manager.rs similarity index 100% rename from crates/bevy_pbr/src/meshlet/meshlet_mesh_manager.rs rename to crates/bevy_render_3d/src/meshlet/meshlet_mesh_manager.rs diff --git a/crates/bevy_pbr/src/meshlet/meshlet_mesh_material.wgsl b/crates/bevy_render_3d/src/meshlet/meshlet_mesh_material.wgsl similarity index 100% rename from crates/bevy_pbr/src/meshlet/meshlet_mesh_material.wgsl rename to crates/bevy_render_3d/src/meshlet/meshlet_mesh_material.wgsl diff --git a/crates/bevy_pbr/src/meshlet/meshlet_preview.png b/crates/bevy_render_3d/src/meshlet/meshlet_preview.png similarity index 100% rename from crates/bevy_pbr/src/meshlet/meshlet_preview.png rename to crates/bevy_render_3d/src/meshlet/meshlet_preview.png diff --git a/crates/bevy_pbr/src/meshlet/mod.rs b/crates/bevy_render_3d/src/meshlet/mod.rs similarity index 100% rename from crates/bevy_pbr/src/meshlet/mod.rs rename to crates/bevy_render_3d/src/meshlet/mod.rs diff --git a/crates/bevy_pbr/src/meshlet/persistent_buffer.rs b/crates/bevy_render_3d/src/meshlet/persistent_buffer.rs similarity index 100% rename from crates/bevy_pbr/src/meshlet/persistent_buffer.rs rename to crates/bevy_render_3d/src/meshlet/persistent_buffer.rs diff --git a/crates/bevy_pbr/src/meshlet/persistent_buffer_impls.rs b/crates/bevy_render_3d/src/meshlet/persistent_buffer_impls.rs similarity index 100% rename from crates/bevy_pbr/src/meshlet/persistent_buffer_impls.rs rename to crates/bevy_render_3d/src/meshlet/persistent_buffer_impls.rs diff --git a/crates/bevy_pbr/src/meshlet/pipelines.rs b/crates/bevy_render_3d/src/meshlet/pipelines.rs similarity index 100% rename from crates/bevy_pbr/src/meshlet/pipelines.rs rename to crates/bevy_render_3d/src/meshlet/pipelines.rs diff --git a/crates/bevy_pbr/src/meshlet/remap_1d_to_2d_dispatch.wgsl b/crates/bevy_render_3d/src/meshlet/remap_1d_to_2d_dispatch.wgsl similarity index 100% rename from crates/bevy_pbr/src/meshlet/remap_1d_to_2d_dispatch.wgsl rename to crates/bevy_render_3d/src/meshlet/remap_1d_to_2d_dispatch.wgsl diff --git a/crates/bevy_pbr/src/meshlet/resolve_render_targets.wgsl b/crates/bevy_render_3d/src/meshlet/resolve_render_targets.wgsl similarity index 100% rename from crates/bevy_pbr/src/meshlet/resolve_render_targets.wgsl rename to crates/bevy_render_3d/src/meshlet/resolve_render_targets.wgsl diff --git a/crates/bevy_pbr/src/meshlet/resource_manager.rs b/crates/bevy_render_3d/src/meshlet/resource_manager.rs similarity index 100% rename from crates/bevy_pbr/src/meshlet/resource_manager.rs rename to crates/bevy_render_3d/src/meshlet/resource_manager.rs diff --git a/crates/bevy_pbr/src/meshlet/visibility_buffer_hardware_raster.wgsl b/crates/bevy_render_3d/src/meshlet/visibility_buffer_hardware_raster.wgsl similarity index 100% rename from crates/bevy_pbr/src/meshlet/visibility_buffer_hardware_raster.wgsl rename to crates/bevy_render_3d/src/meshlet/visibility_buffer_hardware_raster.wgsl diff --git a/crates/bevy_pbr/src/meshlet/visibility_buffer_raster_node.rs b/crates/bevy_render_3d/src/meshlet/visibility_buffer_raster_node.rs similarity index 100% rename from crates/bevy_pbr/src/meshlet/visibility_buffer_raster_node.rs rename to crates/bevy_render_3d/src/meshlet/visibility_buffer_raster_node.rs diff --git a/crates/bevy_pbr/src/meshlet/visibility_buffer_resolve.wgsl b/crates/bevy_render_3d/src/meshlet/visibility_buffer_resolve.wgsl similarity index 100% rename from crates/bevy_pbr/src/meshlet/visibility_buffer_resolve.wgsl rename to crates/bevy_render_3d/src/meshlet/visibility_buffer_resolve.wgsl diff --git a/crates/bevy_pbr/src/meshlet/visibility_buffer_software_raster.wgsl b/crates/bevy_render_3d/src/meshlet/visibility_buffer_software_raster.wgsl similarity index 100% rename from crates/bevy_pbr/src/meshlet/visibility_buffer_software_raster.wgsl rename to crates/bevy_render_3d/src/meshlet/visibility_buffer_software_raster.wgsl diff --git a/crates/bevy_pbr/src/prepass/mod.rs b/crates/bevy_render_3d/src/prepass/mod.rs similarity index 98% rename from crates/bevy_pbr/src/prepass/mod.rs rename to crates/bevy_render_3d/src/prepass/mod.rs index 7b70df38aab70..5abc93a3fef4c 100644 --- a/crates/bevy_pbr/src/prepass/mod.rs +++ b/crates/bevy_render_3d/src/prepass/mod.rs @@ -3,11 +3,11 @@ mod prepass_bindings; use crate::{ alpha_mode_pipeline_key, binding_arrays_are_usable, buffer_layout, collect_meshes_for_gpu_building, material_bind_groups::MaterialBindGroupAllocator, - queue_material_meshes, setup_morph_and_skinning_defs, skin, DrawMesh, - EntitySpecializationTicks, Material, MaterialPipeline, MaterialPipelineKey, MeshLayouts, - MeshPipeline, MeshPipelineKey, OpaqueRendererMethod, PreparedMaterial, RenderLightmaps, - RenderMaterialInstances, RenderMeshInstanceFlags, RenderMeshInstances, RenderPhaseType, - SetMaterialBindGroup, SetMeshBindGroup, ShadowView, StandardMaterial, + setup_morph_and_skinning_defs, skin, DrawMesh, EntitySpecializationTicks, Material, + MaterialPipeline, MaterialPipelineKey, MeshLayouts, MeshPipeline, MeshPipelineKey, + OpaqueRendererMethod, PreparedMaterial, RenderLightmaps, RenderMaterialInstances, + RenderMeshInstanceFlags, RenderMeshInstances, RenderPhaseType, SetMaterialBindGroup, + SetMeshBindGroup, ShadowView, }; use bevy_app::{App, Plugin, PreUpdate}; use bevy_render::{ @@ -203,6 +203,13 @@ where ); } + render_app.configure_sets( + Render, + PrepassSet::QueuePrepass + .in_set(RenderSet::QueueMeshes) + .ambiguous_with(PrepassSet::QueuePrepass), + ); + render_app .init_resource::() .init_resource::() @@ -221,10 +228,8 @@ where .after(prepare_assets::) .after(collect_meshes_for_gpu_building), queue_prepass_material_meshes:: - .in_set(RenderSet::QueueMeshes) - .after(prepare_assets::>) - // queue_material_meshes only writes to `material_bind_group_id`, which `queue_prepass_material_meshes` doesn't read - .ambiguous_with(queue_material_meshes::), + .in_set(PrepassSet::QueuePrepass) + .after(prepare_assets::>), ), ); @@ -240,6 +245,11 @@ where } } +#[derive(Debug, Hash, PartialEq, Eq, Clone, SystemSet)] +pub enum PrepassSet { + QueuePrepass, +} + #[derive(Resource)] struct AnyPrepassPluginLoaded; diff --git a/crates/bevy_pbr/src/prepass/prepass.wgsl b/crates/bevy_render_3d/src/prepass/prepass.wgsl similarity index 100% rename from crates/bevy_pbr/src/prepass/prepass.wgsl rename to crates/bevy_render_3d/src/prepass/prepass.wgsl diff --git a/crates/bevy_pbr/src/prepass/prepass_bindings.rs b/crates/bevy_render_3d/src/prepass/prepass_bindings.rs similarity index 100% rename from crates/bevy_pbr/src/prepass/prepass_bindings.rs rename to crates/bevy_render_3d/src/prepass/prepass_bindings.rs diff --git a/crates/bevy_pbr/src/prepass/prepass_bindings.wgsl b/crates/bevy_render_3d/src/prepass/prepass_bindings.wgsl similarity index 100% rename from crates/bevy_pbr/src/prepass/prepass_bindings.wgsl rename to crates/bevy_render_3d/src/prepass/prepass_bindings.wgsl diff --git a/crates/bevy_pbr/src/prepass/prepass_io.wgsl b/crates/bevy_render_3d/src/prepass/prepass_io.wgsl similarity index 100% rename from crates/bevy_pbr/src/prepass/prepass_io.wgsl rename to crates/bevy_render_3d/src/prepass/prepass_io.wgsl diff --git a/crates/bevy_pbr/src/prepass/prepass_utils.wgsl b/crates/bevy_render_3d/src/prepass/prepass_utils.wgsl similarity index 100% rename from crates/bevy_pbr/src/prepass/prepass_utils.wgsl rename to crates/bevy_render_3d/src/prepass/prepass_utils.wgsl diff --git a/crates/bevy_pbr/src/render/build_indirect_params.wgsl b/crates/bevy_render_3d/src/render/build_indirect_params.wgsl similarity index 100% rename from crates/bevy_pbr/src/render/build_indirect_params.wgsl rename to crates/bevy_render_3d/src/render/build_indirect_params.wgsl diff --git a/crates/bevy_pbr/src/render/clustered_forward.wgsl b/crates/bevy_render_3d/src/render/clustered_forward.wgsl similarity index 100% rename from crates/bevy_pbr/src/render/clustered_forward.wgsl rename to crates/bevy_render_3d/src/render/clustered_forward.wgsl diff --git a/crates/bevy_pbr/src/render/fog.rs b/crates/bevy_render_3d/src/render/fog.rs similarity index 100% rename from crates/bevy_pbr/src/render/fog.rs rename to crates/bevy_render_3d/src/render/fog.rs diff --git a/crates/bevy_pbr/src/render/fog.wgsl b/crates/bevy_render_3d/src/render/fog.wgsl similarity index 100% rename from crates/bevy_pbr/src/render/fog.wgsl rename to crates/bevy_render_3d/src/render/fog.wgsl diff --git a/crates/bevy_pbr/src/render/forward_io.wgsl b/crates/bevy_render_3d/src/render/forward_io.wgsl similarity index 100% rename from crates/bevy_pbr/src/render/forward_io.wgsl rename to crates/bevy_render_3d/src/render/forward_io.wgsl diff --git a/crates/bevy_pbr/src/render/gpu_preprocess.rs b/crates/bevy_render_3d/src/render/gpu_preprocess.rs similarity index 100% rename from crates/bevy_pbr/src/render/gpu_preprocess.rs rename to crates/bevy_render_3d/src/render/gpu_preprocess.rs diff --git a/crates/bevy_pbr/src/render/light.rs b/crates/bevy_render_3d/src/render/light.rs similarity index 100% rename from crates/bevy_pbr/src/render/light.rs rename to crates/bevy_render_3d/src/render/light.rs diff --git a/crates/bevy_pbr/src/render/mesh.rs b/crates/bevy_render_3d/src/render/mesh.rs similarity index 99% rename from crates/bevy_pbr/src/render/mesh.rs rename to crates/bevy_render_3d/src/render/mesh.rs index a87bde7753cf5..0fc744a83a573 100644 --- a/crates/bevy_pbr/src/render/mesh.rs +++ b/crates/bevy_render_3d/src/render/mesh.rs @@ -101,6 +101,15 @@ impl MeshRenderPlugin { } } +impl Default for MeshRenderPlugin { + fn default() -> Self { + Self { + use_gpu_instance_buffer_builder: true, + debug_flags: default(), + } + } +} + pub const FORWARD_IO_HANDLE: Handle = weak_handle!("38111de1-6e35-4dbb-877b-7b6f9334baf6"); pub const MESH_VIEW_TYPES_HANDLE: Handle = weak_handle!("979493db-4ae1-4003-b5c6-fcbb88b152a2"); @@ -914,7 +923,8 @@ impl RenderMeshMaterialIds { self.mesh_to_material .get(&entity) .cloned() - .unwrap_or(AssetId::::invalid().into()) + // All assets have the same invalid AssetId + .unwrap_or(AssetId::::invalid().into()) } pub(crate) fn insert(&mut self, mesh_entity: MainEntity, material_id: UntypedAssetId) { diff --git a/crates/bevy_pbr/src/render/mesh.wgsl b/crates/bevy_render_3d/src/render/mesh.wgsl similarity index 100% rename from crates/bevy_pbr/src/render/mesh.wgsl rename to crates/bevy_render_3d/src/render/mesh.wgsl diff --git a/crates/bevy_pbr/src/render/mesh_bindings.rs b/crates/bevy_render_3d/src/render/mesh_bindings.rs similarity index 100% rename from crates/bevy_pbr/src/render/mesh_bindings.rs rename to crates/bevy_render_3d/src/render/mesh_bindings.rs diff --git a/crates/bevy_pbr/src/render/mesh_bindings.wgsl b/crates/bevy_render_3d/src/render/mesh_bindings.wgsl similarity index 100% rename from crates/bevy_pbr/src/render/mesh_bindings.wgsl rename to crates/bevy_render_3d/src/render/mesh_bindings.wgsl diff --git a/crates/bevy_pbr/src/render/mesh_functions.wgsl b/crates/bevy_render_3d/src/render/mesh_functions.wgsl similarity index 100% rename from crates/bevy_pbr/src/render/mesh_functions.wgsl rename to crates/bevy_render_3d/src/render/mesh_functions.wgsl diff --git a/crates/bevy_pbr/src/render/mesh_preprocess.wgsl b/crates/bevy_render_3d/src/render/mesh_preprocess.wgsl similarity index 100% rename from crates/bevy_pbr/src/render/mesh_preprocess.wgsl rename to crates/bevy_render_3d/src/render/mesh_preprocess.wgsl diff --git a/crates/bevy_pbr/src/render/mesh_types.wgsl b/crates/bevy_render_3d/src/render/mesh_types.wgsl similarity index 100% rename from crates/bevy_pbr/src/render/mesh_types.wgsl rename to crates/bevy_render_3d/src/render/mesh_types.wgsl diff --git a/crates/bevy_pbr/src/render/mesh_view_bindings.rs b/crates/bevy_render_3d/src/render/mesh_view_bindings.rs similarity index 100% rename from crates/bevy_pbr/src/render/mesh_view_bindings.rs rename to crates/bevy_render_3d/src/render/mesh_view_bindings.rs diff --git a/crates/bevy_pbr/src/render/mesh_view_bindings.wgsl b/crates/bevy_render_3d/src/render/mesh_view_bindings.wgsl similarity index 100% rename from crates/bevy_pbr/src/render/mesh_view_bindings.wgsl rename to crates/bevy_render_3d/src/render/mesh_view_bindings.wgsl diff --git a/crates/bevy_pbr/src/render/mesh_view_types.wgsl b/crates/bevy_render_3d/src/render/mesh_view_types.wgsl similarity index 100% rename from crates/bevy_pbr/src/render/mesh_view_types.wgsl rename to crates/bevy_render_3d/src/render/mesh_view_types.wgsl diff --git a/crates/bevy_pbr/src/render/mod.rs b/crates/bevy_render_3d/src/render/mod.rs similarity index 100% rename from crates/bevy_pbr/src/render/mod.rs rename to crates/bevy_render_3d/src/render/mod.rs diff --git a/crates/bevy_pbr/src/render/morph.rs b/crates/bevy_render_3d/src/render/morph.rs similarity index 100% rename from crates/bevy_pbr/src/render/morph.rs rename to crates/bevy_render_3d/src/render/morph.rs diff --git a/crates/bevy_pbr/src/render/morph.wgsl b/crates/bevy_render_3d/src/render/morph.wgsl similarity index 100% rename from crates/bevy_pbr/src/render/morph.wgsl rename to crates/bevy_render_3d/src/render/morph.wgsl diff --git a/crates/bevy_pbr/src/render/occlusion_culling.wgsl b/crates/bevy_render_3d/src/render/occlusion_culling.wgsl similarity index 100% rename from crates/bevy_pbr/src/render/occlusion_culling.wgsl rename to crates/bevy_render_3d/src/render/occlusion_culling.wgsl diff --git a/crates/bevy_render_3d/src/render/parallax_mapping.wgsl b/crates/bevy_render_3d/src/render/parallax_mapping.wgsl new file mode 100644 index 0000000000000..9005734da5cc1 --- /dev/null +++ b/crates/bevy_render_3d/src/render/parallax_mapping.wgsl @@ -0,0 +1,139 @@ +#define_import_path bevy_pbr::parallax_mapping + +#import bevy_render::bindless::{bindless_samplers_filtering, bindless_textures_2d} + +#import bevy_pbr::{ + pbr_bindings::{depth_map_texture, depth_map_sampler}, + mesh_bindings::mesh +} + +#ifdef BINDLESS +#import bevy_pbr::pbr_bindings::material_indices +#endif // BINDLESS + +fn sample_depth_map(uv: vec2, material_bind_group_slot: u32) -> f32 { + // We use `textureSampleLevel` over `textureSample` because the wgpu DX12 + // backend (Fxc) panics when using "gradient instructions" inside a loop. + // It results in the whole loop being unrolled by the shader compiler, + // which it can't do because the upper limit of the loop in steep parallax + // mapping is a variable set by the user. + // The "gradient instructions" comes from `textureSample` computing MIP level + // based on UV derivative. With `textureSampleLevel`, we provide ourselves + // the MIP level, so no gradient instructions are used, and we can use + // sample_depth_map in our loop. + // See https://stackoverflow.com/questions/56581141/direct3d11-gradient-instruction-used-in-a-loop-with-varying-iteration-forcing + return textureSampleLevel( +#ifdef BINDLESS + bindless_textures_2d[material_indices[material_bind_group_slot].depth_map_texture], + bindless_samplers_filtering[material_indices[material_bind_group_slot].depth_map_sampler], +#else // BINDLESS + depth_map_texture, + depth_map_sampler, +#endif // BINDLESS + uv, + 0.0 + ).r; +} + +// An implementation of parallax mapping, see https://en.wikipedia.org/wiki/Parallax_mapping +// Code derived from: https://web.archive.org/web/20150419215321/http://sunandblackcat.com/tipFullView.php?l=eng&topicid=28 +fn parallaxed_uv( + depth_scale: f32, + max_layer_count: f32, + max_steps: u32, + // The original interpolated uv + original_uv: vec2, + // The vector from the camera to the fragment at the surface in tangent space + Vt: vec3, + material_bind_group_slot: u32, +) -> vec2 { + if max_layer_count < 1.0 { + return original_uv; + } + var uv = original_uv; + + // Steep Parallax Mapping + // ====================== + // Split the depth map into `layer_count` layers. + // When Vt hits the surface of the mesh (excluding depth displacement), + // if the depth is not below or on surface including depth displacement (textureSample), then + // look forward (+= delta_uv) on depth texture according to + // Vt and distance between hit surface and depth map surface, + // repeat until below the surface. + // + // Where `layer_count` is interpolated between `1.0` and + // `max_layer_count` according to the steepness of Vt. + + let view_steepness = abs(Vt.z); + // We mix with minimum value 1.0 because otherwise, + // with 0.0, we get a division by zero in surfaces parallel to viewport, + // resulting in a singularity. + let layer_count = mix(max_layer_count, 1.0, view_steepness); + let layer_depth = 1.0 / layer_count; + var delta_uv = depth_scale * layer_depth * Vt.xy * vec2(1.0, -1.0) / view_steepness; + + var current_layer_depth = 0.0; + var texture_depth = sample_depth_map(uv, material_bind_group_slot); + + // texture_depth > current_layer_depth means the depth map depth is deeper + // than the depth the ray would be at this UV offset so the ray has not + // intersected the surface + for (var i: i32 = 0; texture_depth > current_layer_depth && i <= i32(layer_count); i++) { + current_layer_depth += layer_depth; + uv += delta_uv; + texture_depth = sample_depth_map(uv, material_bind_group_slot); + } + +#ifdef RELIEF_MAPPING + // Relief Mapping + // ============== + // "Refine" the rough result from Steep Parallax Mapping + // with a **binary search** between the layer selected by steep parallax + // and the next one to find a point closer to the depth map surface. + // This reduces the jaggy step artifacts from steep parallax mapping. + + delta_uv *= 0.5; + var delta_depth = 0.5 * layer_depth; + + uv -= delta_uv; + current_layer_depth -= delta_depth; + + for (var i: u32 = 0u; i < max_steps; i++) { + texture_depth = sample_depth_map(uv, material_bind_group_slot); + + // Halve the deltas for the next step + delta_uv *= 0.5; + delta_depth *= 0.5; + + // Step based on whether the current depth is above or below the depth map + if (texture_depth > current_layer_depth) { + uv += delta_uv; + current_layer_depth += delta_depth; + } else { + uv -= delta_uv; + current_layer_depth -= delta_depth; + } + } +#else + // Parallax Occlusion mapping + // ========================== + // "Refine" Steep Parallax Mapping by interpolating between the + // previous layer's depth and the computed layer depth. + // Only requires a single lookup, unlike Relief Mapping, but + // may skip small details and result in writhing material artifacts. + let previous_uv = uv - delta_uv; + let next_depth = texture_depth - current_layer_depth; + let previous_depth = sample_depth_map(previous_uv, material_bind_group_slot) - + current_layer_depth + layer_depth; + + let weight = next_depth / (next_depth - previous_depth); + + uv = mix(uv, previous_uv, weight); + + current_layer_depth += mix(next_depth, previous_depth, weight); +#endif + + // Note: `current_layer_depth` is not returned, but may be useful + // for light computation later on in future improvements of the pbr shader. + return uv; +} diff --git a/crates/bevy_render_3d/src/render/pbr.wgsl b/crates/bevy_render_3d/src/render/pbr.wgsl new file mode 100644 index 0000000000000..1722ab9d91940 --- /dev/null +++ b/crates/bevy_render_3d/src/render/pbr.wgsl @@ -0,0 +1,107 @@ +#import bevy_pbr::{ + pbr_types, + pbr_functions::alpha_discard, + pbr_fragment::pbr_input_from_standard_material, + decal::clustered::apply_decal_base_color, +} + +#ifdef PREPASS_PIPELINE +#import bevy_pbr::{ + prepass_io::{VertexOutput, FragmentOutput}, + pbr_deferred_functions::deferred_output, +} +#else +#import bevy_pbr::{ + forward_io::{VertexOutput, FragmentOutput}, + pbr_functions, + pbr_functions::{apply_pbr_lighting, main_pass_post_lighting_processing}, + pbr_types::STANDARD_MATERIAL_FLAGS_UNLIT_BIT, +} +#endif + +#ifdef MESHLET_MESH_MATERIAL_PASS +#import bevy_pbr::meshlet_visibility_buffer_resolve::resolve_vertex_output +#endif + +#ifdef OIT_ENABLED +#import bevy_core_pipeline::oit::oit_draw +#endif // OIT_ENABLED + +#ifdef FORWARD_DECAL +#import bevy_pbr::decal::forward::get_forward_decal_info +#endif + +@fragment +fn fragment( +#ifdef MESHLET_MESH_MATERIAL_PASS + @builtin(position) frag_coord: vec4, +#else + vertex_output: VertexOutput, + @builtin(front_facing) is_front: bool, +#endif +) -> FragmentOutput { +#ifdef MESHLET_MESH_MATERIAL_PASS + let vertex_output = resolve_vertex_output(frag_coord); + let is_front = true; +#endif + + var in = vertex_output; + + // If we're in the crossfade section of a visibility range, conditionally + // discard the fragment according to the visibility pattern. +#ifdef VISIBILITY_RANGE_DITHER + pbr_functions::visibility_range_dither(in.position, in.visibility_range_dither); +#endif + +#ifdef FORWARD_DECAL + let forward_decal_info = get_forward_decal_info(in); + in.world_position = forward_decal_info.world_position; + in.uv = forward_decal_info.uv; +#endif + + // generate a PbrInput struct from the StandardMaterial bindings + var pbr_input = pbr_input_from_standard_material(in, is_front); + + // alpha discard + pbr_input.material.base_color = alpha_discard(pbr_input.material, pbr_input.material.base_color); + + // clustered decals + pbr_input.material.base_color = apply_decal_base_color( + in.world_position.xyz, + in.position.xy, + pbr_input.material.base_color + ); + +#ifdef PREPASS_PIPELINE + // write the gbuffer, lighting pass id, and optionally normal and motion_vector textures + let out = deferred_output(in, pbr_input); +#else + // in forward mode, we calculate the lit color immediately, and then apply some post-lighting effects here. + // in deferred mode the lit color and these effects will be calculated in the deferred lighting shader + var out: FragmentOutput; + if (pbr_input.material.flags & STANDARD_MATERIAL_FLAGS_UNLIT_BIT) == 0u { + out.color = apply_pbr_lighting(pbr_input); + } else { + out.color = pbr_input.material.base_color; + } + + // apply in-shader post processing (fog, alpha-premultiply, and also tonemapping, debanding if the camera is non-hdr) + // note this does not include fullscreen postprocessing effects like bloom. + out.color = main_pass_post_lighting_processing(pbr_input, out.color); +#endif + +#ifdef OIT_ENABLED + let alpha_mode = pbr_input.material.flags & pbr_types::STANDARD_MATERIAL_FLAGS_ALPHA_MODE_RESERVED_BITS; + if alpha_mode != pbr_types::STANDARD_MATERIAL_FLAGS_ALPHA_MODE_OPAQUE { + // The fragments will only be drawn during the oit resolve pass. + oit_draw(in.position, out.color); + discard; + } +#endif // OIT_ENABLED + +#ifdef FORWARD_DECAL + out.color.a = min(forward_decal_info.alpha, out.color.a); +#endif + + return out; +} diff --git a/crates/bevy_render_3d/src/render/pbr_ambient.wgsl b/crates/bevy_render_3d/src/render/pbr_ambient.wgsl new file mode 100644 index 0000000000000..7b174da35c9db --- /dev/null +++ b/crates/bevy_render_3d/src/render/pbr_ambient.wgsl @@ -0,0 +1,29 @@ +#define_import_path bevy_pbr::ambient + +#import bevy_pbr::{ + lighting::{EnvBRDFApprox, F_AB}, + mesh_view_bindings::lights, +} + +// A precomputed `NdotV` is provided because it is computed regardless, +// but `world_normal` and the view vector `V` are provided separately for more advanced uses. +fn ambient_light( + world_position: vec4, + world_normal: vec3, + V: vec3, + NdotV: f32, + diffuse_color: vec3, + specular_color: vec3, + perceptual_roughness: f32, + occlusion: vec3, +) -> vec3 { + let diffuse_ambient = EnvBRDFApprox(diffuse_color, F_AB(1.0, NdotV)); + let specular_ambient = EnvBRDFApprox(specular_color, F_AB(perceptual_roughness, NdotV)); + + // No real world material has specular values under 0.02, so we use this range as a + // "pre-baked specular occlusion" that extinguishes the fresnel term, for artistic control. + // See: https://google.github.io/filament/Filament.html#specularocclusion + let specular_occlusion = saturate(dot(specular_color, vec3(50.0 * 0.33))); + + return (diffuse_ambient + specular_ambient * specular_occlusion) * lights.ambient_color.rgb * occlusion; +} diff --git a/crates/bevy_render_3d/src/render/pbr_bindings.wgsl b/crates/bevy_render_3d/src/render/pbr_bindings.wgsl new file mode 100644 index 0000000000000..d5cd3b03c1352 --- /dev/null +++ b/crates/bevy_render_3d/src/render/pbr_bindings.wgsl @@ -0,0 +1,97 @@ +#define_import_path bevy_pbr::pbr_bindings + +#import bevy_pbr::pbr_types::StandardMaterial + +#ifdef BINDLESS +struct StandardMaterialBindings { + material: u32, // 0 + base_color_texture: u32, // 1 + base_color_sampler: u32, // 2 + emissive_texture: u32, // 3 + emissive_sampler: u32, // 4 + metallic_roughness_texture: u32, // 5 + metallic_roughness_sampler: u32, // 6 + occlusion_texture: u32, // 7 + occlusion_sampler: u32, // 8 + normal_map_texture: u32, // 9 + normal_map_sampler: u32, // 10 + depth_map_texture: u32, // 11 + depth_map_sampler: u32, // 12 +#ifdef PBR_ANISOTROPY_TEXTURE_SUPPORTED + anisotropy_texture: u32, // 13 + anisotropy_sampler: u32, // 14 +#endif // PBR_ANISOTROPY_TEXTURE_SUPPORTED +#ifdef PBR_TRANSMISSION_TEXTURES_SUPPORTED + specular_transmission_texture: u32, // 15 + specular_transmission_sampler: u32, // 16 + thickness_texture: u32, // 17 + thickness_sampler: u32, // 18 + diffuse_transmission_texture: u32, // 19 + diffuse_transmission_sampler: u32, // 20 +#endif // PBR_TRANSMISSION_TEXTURES_SUPPORTED +#ifdef PBR_MULTI_LAYER_MATERIAL_TEXTURES_SUPPORTED + clearcoat_texture: u32, // 21 + clearcoat_sampler: u32, // 22 + clearcoat_roughness_texture: u32, // 23 + clearcoat_roughness_sampler: u32, // 24 + clearcoat_normal_texture: u32, // 25 + clearcoat_normal_sampler: u32, // 26 +#endif // PBR_MULTI_LAYER_MATERIAL_TEXTURES_SUPPORTED +#ifdef PBR_SPECULAR_TEXTURES_SUPPORTED + specular_texture: u32, // 27 + specular_sampler: u32, // 28 + specular_tint_texture: u32, // 29 + specular_tint_sampler: u32, // 30 +#endif // PBR_SPECULAR_TEXTURES_SUPPORTED +} + +@group(2) @binding(0) var material_indices: array; +@group(2) @binding(10) var material_array: array; + +#else // BINDLESS + +@group(2) @binding(0) var material: StandardMaterial; +@group(2) @binding(1) var base_color_texture: texture_2d; +@group(2) @binding(2) var base_color_sampler: sampler; +@group(2) @binding(3) var emissive_texture: texture_2d; +@group(2) @binding(4) var emissive_sampler: sampler; +@group(2) @binding(5) var metallic_roughness_texture: texture_2d; +@group(2) @binding(6) var metallic_roughness_sampler: sampler; +@group(2) @binding(7) var occlusion_texture: texture_2d; +@group(2) @binding(8) var occlusion_sampler: sampler; +@group(2) @binding(9) var normal_map_texture: texture_2d; +@group(2) @binding(10) var normal_map_sampler: sampler; +@group(2) @binding(11) var depth_map_texture: texture_2d; +@group(2) @binding(12) var depth_map_sampler: sampler; + +#ifdef PBR_ANISOTROPY_TEXTURE_SUPPORTED +@group(2) @binding(13) var anisotropy_texture: texture_2d; +@group(2) @binding(14) var anisotropy_sampler: sampler; +#endif // PBR_ANISOTROPY_TEXTURE_SUPPORTED + +#ifdef PBR_TRANSMISSION_TEXTURES_SUPPORTED +@group(2) @binding(15) var specular_transmission_texture: texture_2d; +@group(2) @binding(16) var specular_transmission_sampler: sampler; +@group(2) @binding(17) var thickness_texture: texture_2d; +@group(2) @binding(18) var thickness_sampler: sampler; +@group(2) @binding(19) var diffuse_transmission_texture: texture_2d; +@group(2) @binding(20) var diffuse_transmission_sampler: sampler; +#endif // PBR_TRANSMISSION_TEXTURES_SUPPORTED + +#ifdef PBR_MULTI_LAYER_MATERIAL_TEXTURES_SUPPORTED +@group(2) @binding(21) var clearcoat_texture: texture_2d; +@group(2) @binding(22) var clearcoat_sampler: sampler; +@group(2) @binding(23) var clearcoat_roughness_texture: texture_2d; +@group(2) @binding(24) var clearcoat_roughness_sampler: sampler; +@group(2) @binding(25) var clearcoat_normal_texture: texture_2d; +@group(2) @binding(26) var clearcoat_normal_sampler: sampler; +#endif // PBR_MULTI_LAYER_MATERIAL_TEXTURES_SUPPORTED + +#ifdef PBR_SPECULAR_TEXTURES_SUPPORTED +@group(2) @binding(27) var specular_texture: texture_2d; +@group(2) @binding(28) var specular_sampler: sampler; +@group(2) @binding(29) var specular_tint_texture: texture_2d; +@group(2) @binding(30) var specular_tint_sampler: sampler; +#endif // PBR_SPECULAR_TEXTURES_SUPPORTED + +#endif // BINDLESS diff --git a/crates/bevy_render_3d/src/render/pbr_fragment.wgsl b/crates/bevy_render_3d/src/render/pbr_fragment.wgsl new file mode 100644 index 0000000000000..779546f8bd67d --- /dev/null +++ b/crates/bevy_render_3d/src/render/pbr_fragment.wgsl @@ -0,0 +1,842 @@ +#define_import_path bevy_pbr::pbr_fragment + +#import bevy_render::bindless::{bindless_samplers_filtering, bindless_textures_2d} + +#import bevy_pbr::{ + pbr_functions, + pbr_functions::SampleBias, + pbr_bindings, + pbr_types, + prepass_utils, + lighting, + mesh_bindings::mesh, + mesh_view_bindings::view, + parallax_mapping::parallaxed_uv, + lightmap::lightmap, +} + +#ifdef SCREEN_SPACE_AMBIENT_OCCLUSION +#import bevy_pbr::mesh_view_bindings::screen_space_ambient_occlusion_texture +#import bevy_pbr::ssao_utils::ssao_multibounce +#endif + +#ifdef MESHLET_MESH_MATERIAL_PASS +#import bevy_pbr::meshlet_visibility_buffer_resolve::VertexOutput +#else ifdef PREPASS_PIPELINE +#import bevy_pbr::prepass_io::VertexOutput +#else +#import bevy_pbr::forward_io::VertexOutput +#endif + +#ifdef BINDLESS +#import bevy_pbr::pbr_bindings::material_indices +#endif // BINDLESS + +// prepare a basic PbrInput from the vertex stage output, mesh binding and view binding +fn pbr_input_from_vertex_output( + in: VertexOutput, + is_front: bool, + double_sided: bool, +) -> pbr_types::PbrInput { + var pbr_input: pbr_types::PbrInput = pbr_types::pbr_input_new(); + +#ifdef MESHLET_MESH_MATERIAL_PASS + pbr_input.flags = in.mesh_flags; +#else + pbr_input.flags = mesh[in.instance_index].flags; +#endif + + pbr_input.is_orthographic = view.clip_from_view[3].w == 1.0; + pbr_input.V = pbr_functions::calculate_view(in.world_position, pbr_input.is_orthographic); + pbr_input.frag_coord = in.position; + pbr_input.world_position = in.world_position; + +#ifdef VERTEX_COLORS + pbr_input.material.base_color = in.color; +#endif + + pbr_input.world_normal = pbr_functions::prepare_world_normal( + in.world_normal, + double_sided, + is_front, + ); + +#ifdef LOAD_PREPASS_NORMALS + pbr_input.N = prepass_utils::prepass_normal(in.position, 0u); +#else + pbr_input.N = normalize(pbr_input.world_normal); +#endif + + return pbr_input; +} + +// Prepare a full PbrInput by sampling all textures to resolve +// the material members +fn pbr_input_from_standard_material( + in: VertexOutput, + is_front: bool, +) -> pbr_types::PbrInput { +#ifdef MESHLET_MESH_MATERIAL_PASS + let slot = in.material_bind_group_slot; +#else // MESHLET_MESH_MATERIAL_PASS + let slot = mesh[in.instance_index].material_and_lightmap_bind_group_slot & 0xffffu; +#endif // MESHLET_MESH_MATERIAL_PASS +#ifdef BINDLESS + let flags = pbr_bindings::material_array[material_indices[slot].material].flags; + let base_color = pbr_bindings::material_array[material_indices[slot].material].base_color; + let deferred_lighting_pass_id = + pbr_bindings::material_array[material_indices[slot].material].deferred_lighting_pass_id; +#else // BINDLESS + let flags = pbr_bindings::material.flags; + let base_color = pbr_bindings::material.base_color; + let deferred_lighting_pass_id = pbr_bindings::material.deferred_lighting_pass_id; +#endif + + let double_sided = (flags & pbr_types::STANDARD_MATERIAL_FLAGS_DOUBLE_SIDED_BIT) != 0u; + + var pbr_input: pbr_types::PbrInput = pbr_input_from_vertex_output(in, is_front, double_sided); + pbr_input.material.flags = flags; + pbr_input.material.base_color *= base_color; + pbr_input.material.deferred_lighting_pass_id = deferred_lighting_pass_id; + + // Neubelt and Pettineo 2013, "Crafting a Next-gen Material Pipeline for The Order: 1886" + let NdotV = max(dot(pbr_input.N, pbr_input.V), 0.0001); + + // Fill in the sample bias so we can sample from textures. + var bias: SampleBias; +#ifdef MESHLET_MESH_MATERIAL_PASS + bias.ddx_uv = in.ddx_uv; + bias.ddy_uv = in.ddy_uv; +#else // MESHLET_MESH_MATERIAL_PASS + bias.mip_bias = view.mip_bias; +#endif // MESHLET_MESH_MATERIAL_PASS + +// TODO: Transforming UVs mean we need to apply derivative chain rule for meshlet mesh material pass +#ifdef VERTEX_UVS + +#ifdef BINDLESS + let uv_transform = pbr_bindings::material_array[material_indices[slot].material].uv_transform; +#else // BINDLESS + let uv_transform = pbr_bindings::material.uv_transform; +#endif // BINDLESS + +#ifdef VERTEX_UVS_A + var uv = (uv_transform * vec3(in.uv, 1.0)).xy; +#endif + +// TODO: Transforming UVs mean we need to apply derivative chain rule for meshlet mesh material pass +#ifdef VERTEX_UVS_B + var uv_b = (uv_transform * vec3(in.uv_b, 1.0)).xy; +#else + var uv_b = uv; +#endif + +#ifdef VERTEX_TANGENTS + if ((flags & pbr_types::STANDARD_MATERIAL_FLAGS_DEPTH_MAP_BIT) != 0u) { + let V = pbr_input.V; + let TBN = pbr_functions::calculate_tbn_mikktspace(in.world_normal, in.world_tangent); + let T = TBN[0]; + let B = TBN[1]; + let N = TBN[2]; + // Transform V from fragment to camera in world space to tangent space. + let Vt = vec3(dot(V, T), dot(V, B), dot(V, N)); +#ifdef VERTEX_UVS_A + // TODO: Transforming UVs mean we need to apply derivative chain rule for meshlet mesh material pass + uv = parallaxed_uv( +#ifdef BINDLESS + pbr_bindings::material_array[material_indices[slot].material].parallax_depth_scale, + pbr_bindings::material_array[material_indices[slot].material].max_parallax_layer_count, + pbr_bindings::material_array[material_indices[slot].material].max_relief_mapping_search_steps, +#else // BINDLESS + pbr_bindings::material.parallax_depth_scale, + pbr_bindings::material.max_parallax_layer_count, + pbr_bindings::material.max_relief_mapping_search_steps, +#endif // BINDLESS + uv, + // Flip the direction of Vt to go toward the surface to make the + // parallax mapping algorithm easier to understand and reason + // about. + -Vt, + slot, + ); +#endif + +#ifdef VERTEX_UVS_B + // TODO: Transforming UVs mean we need to apply derivative chain rule for meshlet mesh material pass + uv_b = parallaxed_uv( +#ifdef BINDLESS + pbr_bindings::material_array[material_indices[slot].material].parallax_depth_scale, + pbr_bindings::material_array[material_indices[slot].material].max_parallax_layer_count, + pbr_bindings::material_array[material_indices[slot].material].max_relief_mapping_search_steps, +#else // BINDLESS + pbr_bindings::material.parallax_depth_scale, + pbr_bindings::material.max_parallax_layer_count, + pbr_bindings::material.max_relief_mapping_search_steps, +#endif // BINDLESS + uv_b, + // Flip the direction of Vt to go toward the surface to make the + // parallax mapping algorithm easier to understand and reason + // about. + -Vt, + slot, + ); +#else + uv_b = uv; +#endif + } +#endif // VERTEX_TANGENTS + + if ((flags & pbr_types::STANDARD_MATERIAL_FLAGS_BASE_COLOR_TEXTURE_BIT) != 0u) { + pbr_input.material.base_color *= +#ifdef MESHLET_MESH_MATERIAL_PASS + textureSampleGrad( +#else // MESHLET_MESH_MATERIAL_PASS + textureSampleBias( +#endif // MESHLET_MESH_MATERIAL_PASS +#ifdef BINDLESS + bindless_textures_2d[material_indices[slot].base_color_texture], + bindless_samplers_filtering[material_indices[slot].base_color_sampler], +#else // BINDLESS + pbr_bindings::base_color_texture, + pbr_bindings::base_color_sampler, +#endif // BINDLESS +#ifdef STANDARD_MATERIAL_BASE_COLOR_UV_B + uv_b, +#else + uv, +#endif +#ifdef MESHLET_MESH_MATERIAL_PASS + bias.ddx_uv, + bias.ddy_uv, +#else // MESHLET_MESH_MATERIAL_PASS + bias.mip_bias, +#endif // MESHLET_MESH_MATERIAL_PASS + ); + +#ifdef ALPHA_TO_COVERAGE + // Sharpen alpha edges. + // + // https://bgolus.medium.com/anti-aliased-alpha-test-the-esoteric-alpha-to-coverage-8b177335ae4f + let alpha_mode = flags & pbr_types::STANDARD_MATERIAL_FLAGS_ALPHA_MODE_RESERVED_BITS; + if alpha_mode == pbr_types::STANDARD_MATERIAL_FLAGS_ALPHA_MODE_ALPHA_TO_COVERAGE { + +#ifdef BINDLESS + let alpha_cutoff = pbr_bindings::material_array[material_indices[slot].material].alpha_cutoff; +#else // BINDLESS + let alpha_cutoff = pbr_bindings::material.alpha_cutoff; +#endif // BINDLESS + + pbr_input.material.base_color.a = (pbr_input.material.base_color.a - alpha_cutoff) / + max(fwidth(pbr_input.material.base_color.a), 0.0001) + 0.5; + } +#endif // ALPHA_TO_COVERAGE + + } +#endif // VERTEX_UVS + + pbr_input.material.flags = flags; + + // NOTE: Unlit bit not set means == 0 is true, so the true case is if lit + if ((flags & pbr_types::STANDARD_MATERIAL_FLAGS_UNLIT_BIT) == 0u) { +#ifdef BINDLESS + pbr_input.material.ior = pbr_bindings::material_array[material_indices[slot].material].ior; + pbr_input.material.attenuation_color = + pbr_bindings::material_array[material_indices[slot].material].attenuation_color; + pbr_input.material.attenuation_distance = + pbr_bindings::material_array[material_indices[slot].material].attenuation_distance; + pbr_input.material.alpha_cutoff = + pbr_bindings::material_array[material_indices[slot].material].alpha_cutoff; +#else // BINDLESS + pbr_input.material.ior = pbr_bindings::material.ior; + pbr_input.material.attenuation_color = pbr_bindings::material.attenuation_color; + pbr_input.material.attenuation_distance = pbr_bindings::material.attenuation_distance; + pbr_input.material.alpha_cutoff = pbr_bindings::material.alpha_cutoff; +#endif // BINDLESS + + // reflectance +#ifdef BINDLESS + pbr_input.material.reflectance = + pbr_bindings::material_array[material_indices[slot].material].reflectance; +#else // BINDLESS + pbr_input.material.reflectance = pbr_bindings::material.reflectance; +#endif // BINDLESS + +#ifdef PBR_SPECULAR_TEXTURES_SUPPORTED +#ifdef VERTEX_UVS + + // Specular texture + if ((flags & pbr_types::STANDARD_MATERIAL_FLAGS_SPECULAR_TEXTURE_BIT) != 0u) { + let specular = +#ifdef MESHLET_MESH_MATERIAL_PASS + textureSampleGrad( +#else // MESHLET_MESH_MATERIAL_PASS + textureSampleBias( +#endif // MESHLET_MESH_MATERIAL_PASS +#ifdef BINDLESS + bindless_textures_2d[material_indices[slot].specular_texture], + bindless_samplers_filtering[material_indices[slot].specular_sampler], +#else // BINDLESS + pbr_bindings::specular_texture, + pbr_bindings::specular_sampler, +#endif // BINDLESS +#ifdef STANDARD_MATERIAL_SPECULAR_UV_B + uv_b, +#else // STANDARD_MATERIAL_SPECULAR_UV_B + uv, +#endif // STANDARD_MATERIAL_SPECULAR_UV_B +#ifdef MESHLET_MESH_MATERIAL_PASS + bias.ddx_uv, + bias.ddy_uv, +#else // MESHLET_MESH_MATERIAL_PASS + bias.mip_bias, +#endif // MESHLET_MESH_MATERIAL_PASS + ).a; + // This 0.5 factor is from the `KHR_materials_specular` specification: + // + pbr_input.material.reflectance *= specular * 0.5; + } + + // Specular tint texture + if ((flags & pbr_types::STANDARD_MATERIAL_FLAGS_SPECULAR_TINT_TEXTURE_BIT) != 0u) { + let specular_tint = +#ifdef MESHLET_MESH_MATERIAL_PASS + textureSampleGrad( +#else // MESHLET_MESH_MATERIAL_PASS + textureSampleBias( +#endif // MESHLET_MESH_MATERIAL_PASS +#ifdef BINDLESS + bindless_textures_2d[material_indices[slot].specular_tint_texture], + bindless_samplers_filtering[material_indices[slot].specular_tint_sampler], +#else // BINDLESS + pbr_bindings::specular_tint_texture, + pbr_bindings::specular_tint_sampler, +#endif // BINDLESS +#ifdef STANDARD_MATERIAL_SPECULAR_TINT_UV_B + uv_b, +#else // STANDARD_MATERIAL_SPECULAR_TINT_UV_B + uv, +#endif // STANDARD_MATERIAL_SPECULAR_TINT_UV_B +#ifdef MESHLET_MESH_MATERIAL_PASS + bias.ddx_uv, + bias.ddy_uv, +#else // MESHLET_MESH_MATERIAL_PASS + bias.mip_bias, +#endif // MESHLET_MESH_MATERIAL_PASS + ).rgb; + pbr_input.material.reflectance *= specular_tint; + } + +#endif // VERTEX_UVS +#endif // PBR_SPECULAR_TEXTURES_SUPPORTED + + // emissive +#ifdef BINDLESS + var emissive: vec4 = pbr_bindings::material_array[material_indices[slot].material].emissive; +#else // BINDLESS + var emissive: vec4 = pbr_bindings::material.emissive; +#endif // BINDLESS + +#ifdef VERTEX_UVS + if ((flags & pbr_types::STANDARD_MATERIAL_FLAGS_EMISSIVE_TEXTURE_BIT) != 0u) { + emissive = vec4(emissive.rgb * +#ifdef MESHLET_MESH_MATERIAL_PASS + textureSampleGrad( +#else // MESHLET_MESH_MATERIAL_PASS + textureSampleBias( +#endif // MESHLET_MESH_MATERIAL_PASS +#ifdef BINDLESS + bindless_textures_2d[material_indices[slot].emissive_texture], + bindless_samplers_filtering[material_indices[slot].emissive_sampler], +#else // BINDLESS + pbr_bindings::emissive_texture, + pbr_bindings::emissive_sampler, +#endif // BINDLESS +#ifdef STANDARD_MATERIAL_EMISSIVE_UV_B + uv_b, +#else + uv, +#endif +#ifdef MESHLET_MESH_MATERIAL_PASS + bias.ddx_uv, + bias.ddy_uv, +#else // MESHLET_MESH_MATERIAL_PASS + bias.mip_bias, +#endif // MESHLET_MESH_MATERIAL_PASS + ).rgb, + emissive.a); + } +#endif + pbr_input.material.emissive = emissive; + + // metallic and perceptual roughness +#ifdef BINDLESS + var metallic: f32 = pbr_bindings::material_array[material_indices[slot].material].metallic; + var perceptual_roughness: f32 = pbr_bindings::material_array[material_indices[slot].material].perceptual_roughness; +#else // BINDLESS + var metallic: f32 = pbr_bindings::material.metallic; + var perceptual_roughness: f32 = pbr_bindings::material.perceptual_roughness; +#endif // BINDLESS + + let roughness = lighting::perceptualRoughnessToRoughness(perceptual_roughness); +#ifdef VERTEX_UVS + if ((flags & pbr_types::STANDARD_MATERIAL_FLAGS_METALLIC_ROUGHNESS_TEXTURE_BIT) != 0u) { + let metallic_roughness = +#ifdef MESHLET_MESH_MATERIAL_PASS + textureSampleGrad( +#else // MESHLET_MESH_MATERIAL_PASS + textureSampleBias( +#endif // MESHLET_MESH_MATERIAL_PASS +#ifdef BINDLESS + bindless_textures_2d[material_indices[slot].metallic_roughness_texture], + bindless_samplers_filtering[material_indices[slot].metallic_roughness_sampler], +#else // BINDLESS + pbr_bindings::metallic_roughness_texture, + pbr_bindings::metallic_roughness_sampler, +#endif // BINDLESS +#ifdef STANDARD_MATERIAL_METALLIC_ROUGHNESS_UV_B + uv_b, +#else + uv, +#endif +#ifdef MESHLET_MESH_MATERIAL_PASS + bias.ddx_uv, + bias.ddy_uv, +#else // MESHLET_MESH_MATERIAL_PASS + bias.mip_bias, +#endif // MESHLET_MESH_MATERIAL_PASS + ); + // Sampling from GLTF standard channels for now + metallic *= metallic_roughness.b; + perceptual_roughness *= metallic_roughness.g; + } +#endif + pbr_input.material.metallic = metallic; + pbr_input.material.perceptual_roughness = perceptual_roughness; + + // Clearcoat factor +#ifdef BINDLESS + pbr_input.material.clearcoat = + pbr_bindings::material_array[material_indices[slot].material].clearcoat; +#else // BINDLESS + pbr_input.material.clearcoat = pbr_bindings::material.clearcoat; +#endif // BINDLESS + +#ifdef VERTEX_UVS +#ifdef PBR_MULTI_LAYER_MATERIAL_TEXTURES_SUPPORTED + if ((flags & pbr_types::STANDARD_MATERIAL_FLAGS_CLEARCOAT_TEXTURE_BIT) != 0u) { + pbr_input.material.clearcoat *= +#ifdef MESHLET_MESH_MATERIAL_PASS + textureSampleGrad( +#else // MESHLET_MESH_MATERIAL_PASS + textureSampleBias( +#endif // MESHLET_MESH_MATERIAL_PASS +#ifdef BINDLESS + bindless_textures_2d[material_indices[slot].clearcoat_texture], + bindless_samplers_filtering[material_indices[slot].clearcoat_sampler], +#else // BINDLESS + pbr_bindings::clearcoat_texture, + pbr_bindings::clearcoat_sampler, +#endif // BINDLESS +#ifdef STANDARD_MATERIAL_CLEARCOAT_UV_B + uv_b, +#else + uv, +#endif +#ifdef MESHLET_MESH_MATERIAL_PASS + bias.ddx_uv, + bias.ddy_uv, +#else // MESHLET_MESH_MATERIAL_PASS + bias.mip_bias, +#endif // MESHLET_MESH_MATERIAL_PASS + ).r; + } +#endif // PBR_MULTI_LAYER_MATERIAL_TEXTURES_SUPPORTED +#endif // VERTEX_UVS + + // Clearcoat roughness +#ifdef BINDLESS + pbr_input.material.clearcoat_perceptual_roughness = + pbr_bindings::material_array[material_indices[slot].material].clearcoat_perceptual_roughness; +#else // BINDLESS + pbr_input.material.clearcoat_perceptual_roughness = + pbr_bindings::material.clearcoat_perceptual_roughness; +#endif // BINDLESS + +#ifdef VERTEX_UVS +#ifdef PBR_MULTI_LAYER_MATERIAL_TEXTURES_SUPPORTED + if ((flags & pbr_types::STANDARD_MATERIAL_FLAGS_CLEARCOAT_ROUGHNESS_TEXTURE_BIT) != 0u) { + pbr_input.material.clearcoat_perceptual_roughness *= +#ifdef MESHLET_MESH_MATERIAL_PASS + textureSampleGrad( +#else // MESHLET_MESH_MATERIAL_PASS + textureSampleBias( +#endif // MESHLET_MESH_MATERIAL_PASS +#ifdef BINDLESS + bindless_textures_2d[material_indices[slot].clearcoat_roughness_texture], + bindless_samplers_filtering[material_indices[slot].clearcoat_roughness_sampler], +#else // BINDLESS + pbr_bindings::clearcoat_roughness_texture, + pbr_bindings::clearcoat_roughness_sampler, +#endif // BINDLESS +#ifdef STANDARD_MATERIAL_CLEARCOAT_ROUGHNESS_UV_B + uv_b, +#else + uv, +#endif +#ifdef MESHLET_MESH_MATERIAL_PASS + bias.ddx_uv, + bias.ddy_uv, +#else // MESHLET_MESH_MATERIAL_PASS + bias.mip_bias, +#endif // MESHLET_MESH_MATERIAL_PASS + ).g; + } +#endif // PBR_MULTI_LAYER_MATERIAL_TEXTURES_SUPPORTED +#endif // VERTEX_UVS + +#ifdef BINDLESS + var specular_transmission: f32 = pbr_bindings::material_array[slot].specular_transmission; +#else // BINDLESS + var specular_transmission: f32 = pbr_bindings::material.specular_transmission; +#endif // BINDLESS + +#ifdef VERTEX_UVS +#ifdef PBR_TRANSMISSION_TEXTURES_SUPPORTED + if ((flags & pbr_types::STANDARD_MATERIAL_FLAGS_SPECULAR_TRANSMISSION_TEXTURE_BIT) != 0u) { + specular_transmission *= +#ifdef MESHLET_MESH_MATERIAL_PASS + textureSampleGrad( +#else // MESHLET_MESH_MATERIAL_PASS + textureSampleBias( +#endif // MESHLET_MESH_MATERIAL_PASS +#ifdef BINDLESS + bindless_textures_2d[ + material_indices[slot].specular_transmission_texture + ], + bindless_samplers_filtering[ + material_indices[slot].specular_transmission_sampler + ], +#else // BINDLESS + pbr_bindings::specular_transmission_texture, + pbr_bindings::specular_transmission_sampler, +#endif // BINDLESS +#ifdef STANDARD_MATERIAL_SPECULAR_TRANSMISSION_UV_B + uv_b, +#else + uv, +#endif +#ifdef MESHLET_MESH_MATERIAL_PASS + bias.ddx_uv, + bias.ddy_uv, +#else // MESHLET_MESH_MATERIAL_PASS + bias.mip_bias, +#endif // MESHLET_MESH_MATERIAL_PASS + ).r; + } +#endif +#endif + pbr_input.material.specular_transmission = specular_transmission; + +#ifdef BINDLESS + var thickness: f32 = pbr_bindings::material_array[material_indices[slot].material].thickness; +#else // BINDLESS + var thickness: f32 = pbr_bindings::material.thickness; +#endif // BINDLESS + +#ifdef VERTEX_UVS +#ifdef PBR_TRANSMISSION_TEXTURES_SUPPORTED + if ((flags & pbr_types::STANDARD_MATERIAL_FLAGS_THICKNESS_TEXTURE_BIT) != 0u) { + thickness *= +#ifdef MESHLET_MESH_MATERIAL_PASS + textureSampleGrad( +#else // MESHLET_MESH_MATERIAL_PASS + textureSampleBias( +#endif // MESHLET_MESH_MATERIAL_PASS +#ifdef BINDLESS + bindless_textures_2d[material_indices[slot].thickness_texture], + bindless_samplers_filtering[material_indices[slot].thickness_sampler], +#else // BINDLESS + pbr_bindings::thickness_texture, + pbr_bindings::thickness_sampler, +#endif // BINDLESS +#ifdef STANDARD_MATERIAL_THICKNESS_UV_B + uv_b, +#else + uv, +#endif +#ifdef MESHLET_MESH_MATERIAL_PASS + bias.ddx_uv, + bias.ddy_uv, +#else // MESHLET_MESH_MATERIAL_PASS + bias.mip_bias, +#endif // MESHLET_MESH_MATERIAL_PASS + ).g; + } +#endif +#endif + // scale thickness, accounting for non-uniform scaling (e.g. a “squished” mesh) + // TODO: Meshlet support +#ifndef MESHLET_MESH_MATERIAL_PASS + thickness *= length( + (transpose(mesh[in.instance_index].world_from_local) * vec4(pbr_input.N, 0.0)).xyz + ); +#endif + pbr_input.material.thickness = thickness; + +#ifdef BINDLESS + var diffuse_transmission = + pbr_bindings::material_array[material_indices[slot].material].diffuse_transmission; +#else // BINDLESS + var diffuse_transmission = pbr_bindings::material.diffuse_transmission; +#endif // BINDLESS + +#ifdef VERTEX_UVS +#ifdef PBR_TRANSMISSION_TEXTURES_SUPPORTED + if ((flags & pbr_types::STANDARD_MATERIAL_FLAGS_DIFFUSE_TRANSMISSION_TEXTURE_BIT) != 0u) { + diffuse_transmission *= +#ifdef MESHLET_MESH_MATERIAL_PASS + textureSampleGrad( +#else // MESHLET_MESH_MATERIAL_PASS + textureSampleBias( +#endif // MESHLET_MESH_MATERIAL_PASS +#ifdef BINDLESS + bindless_textures_2d[material_indices[slot].diffuse_transmission_texture], + bindless_samplers_filtering[material_indices[slot].diffuse_transmission_sampler], +#else // BINDLESS + pbr_bindings::diffuse_transmission_texture, + pbr_bindings::diffuse_transmission_sampler, +#endif // BINDLESS +#ifdef STANDARD_MATERIAL_DIFFUSE_TRANSMISSION_UV_B + uv_b, +#else + uv, +#endif +#ifdef MESHLET_MESH_MATERIAL_PASS + bias.ddx_uv, + bias.ddy_uv, +#else // MESHLET_MESH_MATERIAL_PASS + bias.mip_bias, +#endif // MESHLET_MESH_MATERIAL_PASS + ).a; + } +#endif +#endif + pbr_input.material.diffuse_transmission = diffuse_transmission; + + var diffuse_occlusion: vec3 = vec3(1.0); + var specular_occlusion: f32 = 1.0; +#ifdef VERTEX_UVS + if ((flags & pbr_types::STANDARD_MATERIAL_FLAGS_OCCLUSION_TEXTURE_BIT) != 0u) { + diffuse_occlusion *= +#ifdef MESHLET_MESH_MATERIAL_PASS + textureSampleGrad( +#else // MESHLET_MESH_MATERIAL_PASS + textureSampleBias( +#endif // MESHLET_MESH_MATERIAL_PASS +#ifdef BINDLESS + bindless_textures_2d[material_indices[slot].occlusion_texture], + bindless_samplers_filtering[material_indices[slot].occlusion_sampler], +#else // BINDLESS + pbr_bindings::occlusion_texture, + pbr_bindings::occlusion_sampler, +#endif // BINDLESS +#ifdef STANDARD_MATERIAL_OCCLUSION_UV_B + uv_b, +#else + uv, +#endif +#ifdef MESHLET_MESH_MATERIAL_PASS + bias.ddx_uv, + bias.ddy_uv, +#else // MESHLET_MESH_MATERIAL_PASS + bias.mip_bias, +#endif // MESHLET_MESH_MATERIAL_PASS + ).r; + } +#endif +#ifdef SCREEN_SPACE_AMBIENT_OCCLUSION + let ssao = textureLoad(screen_space_ambient_occlusion_texture, vec2(in.position.xy), 0i).r; + let ssao_multibounce = ssao_multibounce(ssao, pbr_input.material.base_color.rgb); + diffuse_occlusion = min(diffuse_occlusion, ssao_multibounce); + // Use SSAO to estimate the specular occlusion. + // Lagarde and Rousiers 2014, "Moving Frostbite to Physically Based Rendering" + specular_occlusion = saturate(pow(NdotV + ssao, exp2(-16.0 * roughness - 1.0)) - 1.0 + ssao); +#endif + pbr_input.diffuse_occlusion = diffuse_occlusion; + pbr_input.specular_occlusion = specular_occlusion; + + // N (normal vector) +#ifndef LOAD_PREPASS_NORMALS + + pbr_input.N = normalize(pbr_input.world_normal); + pbr_input.clearcoat_N = pbr_input.N; + +#ifdef VERTEX_UVS +#ifdef VERTEX_TANGENTS + + let TBN = pbr_functions::calculate_tbn_mikktspace(pbr_input.world_normal, in.world_tangent); + +#ifdef STANDARD_MATERIAL_NORMAL_MAP + + let Nt = +#ifdef MESHLET_MESH_MATERIAL_PASS + textureSampleGrad( +#else // MESHLET_MESH_MATERIAL_PASS + textureSampleBias( +#endif // MESHLET_MESH_MATERIAL_PASS +#ifdef BINDLESS + bindless_textures_2d[material_indices[slot].normal_map_texture], + bindless_samplers_filtering[material_indices[slot].normal_map_sampler], +#else // BINDLESS + pbr_bindings::normal_map_texture, + pbr_bindings::normal_map_sampler, +#endif // BINDLESS +#ifdef STANDARD_MATERIAL_NORMAL_MAP_UV_B + uv_b, +#else + uv, +#endif +#ifdef MESHLET_MESH_MATERIAL_PASS + bias.ddx_uv, + bias.ddy_uv, +#else // MESHLET_MESH_MATERIAL_PASS + bias.mip_bias, +#endif // MESHLET_MESH_MATERIAL_PASS + ).rgb; + + pbr_input.N = pbr_functions::apply_normal_mapping(flags, TBN, double_sided, is_front, Nt); + +#endif // STANDARD_MATERIAL_NORMAL_MAP + +#ifdef STANDARD_MATERIAL_CLEARCOAT + + // Note: `KHR_materials_clearcoat` specifies that, if there's no + // clearcoat normal map, we must set the normal to the mesh's normal, + // and not to the main layer's bumped normal. + +#ifdef STANDARD_MATERIAL_CLEARCOAT_NORMAL_MAP + + let clearcoat_Nt = +#ifdef MESHLET_MESH_MATERIAL_PASS + textureSampleGrad( +#else // MESHLET_MESH_MATERIAL_PASS + textureSampleBias( +#endif // MESHLET_MESH_MATERIAL_PASS +#ifdef BINDLESS + bindless_textures_2d[material_indices[slot].clearcoat_normal_texture], + bindless_samplers_filtering[material_indices[slot].clearcoat_normal_sampler], +#else // BINDLESS + pbr_bindings::clearcoat_normal_texture, + pbr_bindings::clearcoat_normal_sampler, +#endif // BINDLESS +#ifdef STANDARD_MATERIAL_CLEARCOAT_NORMAL_UV_B + uv_b, +#else + uv, +#endif +#ifdef MESHLET_MESH_MATERIAL_PASS + bias.ddx_uv, + bias.ddy_uv, +#else // MESHLET_MESH_MATERIAL_PASS + bias.mip_bias, +#endif // MESHLET_MESH_MATERIAL_PASS + ).rgb; + + pbr_input.clearcoat_N = pbr_functions::apply_normal_mapping( + flags, + TBN, + double_sided, + is_front, + clearcoat_Nt, + ); + +#endif // STANDARD_MATERIAL_CLEARCOAT_NORMAL_MAP + +#endif // STANDARD_MATERIAL_CLEARCOAT + +#endif // VERTEX_TANGENTS +#endif // VERTEX_UVS + + // Take anisotropy into account. + // + // This code comes from the `KHR_materials_anisotropy` spec: + // +#ifdef PBR_ANISOTROPY_TEXTURE_SUPPORTED +#ifdef VERTEX_TANGENTS +#ifdef STANDARD_MATERIAL_ANISOTROPY + +#ifdef BINDLESS + var anisotropy_strength = + pbr_bindings::material_array[material_indices[slot].material].anisotropy_strength; + var anisotropy_direction = + pbr_bindings::material_array[material_indices[slot].material].anisotropy_rotation; +#else // BINDLESS + var anisotropy_strength = pbr_bindings::material.anisotropy_strength; + var anisotropy_direction = pbr_bindings::material.anisotropy_rotation; +#endif // BINDLESS + + // Adjust based on the anisotropy map if there is one. + if ((flags & pbr_types::STANDARD_MATERIAL_FLAGS_ANISOTROPY_TEXTURE_BIT) != 0u) { + let anisotropy_texel = +#ifdef MESHLET_MESH_MATERIAL_PASS + textureSampleGrad( +#else // MESHLET_MESH_MATERIAL_PASS + textureSampleBias( +#endif // MESHLET_MESH_MATERIAL_PASS +#ifdef BINDLESS + bindless_textures_2d[material_indices[slot].anisotropy_texture], + bindless_samplers_filtering[material_indices[slot].anisotropy_sampler], +#else // BINDLESS + pbr_bindings::anisotropy_texture, + pbr_bindings::anisotropy_sampler, +#endif +#ifdef STANDARD_MATERIAL_ANISOTROPY_UV_B + uv_b, +#else // STANDARD_MATERIAL_ANISOTROPY_UV_B + uv, +#endif // STANDARD_MATERIAL_ANISOTROPY_UV_B +#ifdef MESHLET_MESH_MATERIAL_PASS + bias.ddx_uv, + bias.ddy_uv, +#else // MESHLET_MESH_MATERIAL_PASS + bias.mip_bias, +#endif // MESHLET_MESH_MATERIAL_PASS + ).rgb; + + let anisotropy_direction_from_texture = normalize(anisotropy_texel.rg * 2.0 - 1.0); + // Rotate by the anisotropy direction. + anisotropy_direction = + mat2x2(anisotropy_direction.xy, anisotropy_direction.yx * vec2(-1.0, 1.0)) * + anisotropy_direction_from_texture; + anisotropy_strength *= anisotropy_texel.b; + } + + pbr_input.anisotropy_strength = anisotropy_strength; + + let anisotropy_T = normalize(TBN * vec3(anisotropy_direction, 0.0)); + let anisotropy_B = normalize(cross(pbr_input.world_normal, anisotropy_T)); + pbr_input.anisotropy_T = anisotropy_T; + pbr_input.anisotropy_B = anisotropy_B; + +#endif // STANDARD_MATERIAL_ANISOTROPY +#endif // VERTEX_TANGENTS +#endif // PBR_ANISOTROPY_TEXTURE_SUPPORTED + +#endif // LOAD_PREPASS_NORMALS + +// TODO: Meshlet support +#ifdef LIGHTMAP + +#ifdef BINDLESS + let lightmap_exposure = + pbr_bindings::material_array[material_indices[slot].material].lightmap_exposure; +#else // BINDLESS + let lightmap_exposure = pbr_bindings::material.lightmap_exposure; +#endif // BINDLESS + + pbr_input.lightmap_light = lightmap(in.uv_b, lightmap_exposure, in.instance_index); +#endif + } + + return pbr_input; +} diff --git a/crates/bevy_render_3d/src/render/pbr_functions.wgsl b/crates/bevy_render_3d/src/render/pbr_functions.wgsl new file mode 100644 index 0000000000000..dcda30ee79d59 --- /dev/null +++ b/crates/bevy_render_3d/src/render/pbr_functions.wgsl @@ -0,0 +1,885 @@ +#define_import_path bevy_pbr::pbr_functions + +#import bevy_pbr::{ + pbr_types, + pbr_bindings, + mesh_view_bindings as view_bindings, + mesh_view_types, + lighting, + lighting::{LAYER_BASE, LAYER_CLEARCOAT}, + transmission, + clustered_forward as clustering, + shadows, + ambient, + irradiance_volume, + mesh_types::{MESH_FLAGS_SHADOW_RECEIVER_BIT, MESH_FLAGS_TRANSMITTED_SHADOW_RECEIVER_BIT}, +} +#import bevy_render::maths::{E, powsafe} + +#ifdef MESHLET_MESH_MATERIAL_PASS +#import bevy_pbr::meshlet_visibility_buffer_resolve::VertexOutput +#else ifdef PREPASS_PIPELINE +#import bevy_pbr::prepass_io::VertexOutput +#else // PREPASS_PIPELINE +#import bevy_pbr::forward_io::VertexOutput +#endif // PREPASS_PIPELINE + +#ifdef ENVIRONMENT_MAP +#import bevy_pbr::environment_map +#endif + +#ifdef TONEMAP_IN_SHADER +#import bevy_core_pipeline::tonemapping::{tone_mapping, screen_space_dither} +#endif + + +// Biasing info needed to sample from a texture. How this is done depends on +// whether we're rendering meshlets or regular meshes. +struct SampleBias { +#ifdef MESHLET_MESH_MATERIAL_PASS + ddx_uv: vec2, + ddy_uv: vec2, +#else // MESHLET_MESH_MATERIAL_PASS + mip_bias: f32, +#endif // MESHLET_MESH_MATERIAL_PASS +} + +// This is the standard 4x4 ordered dithering pattern from [1]. +// +// We can't use `array, 4>` because they can't be indexed dynamically +// due to Naga limitations. So instead we pack into a single `vec4` and extract +// individual bytes. +// +// [1]: https://en.wikipedia.org/wiki/Ordered_dithering#Threshold_map +const DITHER_THRESHOLD_MAP: vec4 = vec4( + 0x0a020800, + 0x060e040c, + 0x09010b03, + 0x050d070f +); + +// Processes a visibility range dither value and discards the fragment if +// needed. +// +// Visibility ranges, also known as HLODs, are crossfades between different +// levels of detail. +// +// The `dither` value ranges from [-16, 16]. When zooming out, positive values +// are used for meshes that are in the process of disappearing, while negative +// values are used for meshes that are in the process of appearing. In other +// words, when the camera is moving backwards, the `dither` value counts up from +// -16 to 0 when the object is fading in, stays at 0 while the object is +// visible, and then counts up to 16 while the object is fading out. +// Distinguishing between negative and positive values allows the dither +// patterns for different LOD levels of a single mesh to mesh together properly. +#ifdef VISIBILITY_RANGE_DITHER +fn visibility_range_dither(frag_coord: vec4, dither: i32) { + // If `dither` is 0, the object is visible. + if (dither == 0) { + return; + } + + // If `dither` is less than -15 or greater than 15, the object is culled. + if (dither <= -16 || dither >= 16) { + discard; + } + + // Otherwise, check the dither pattern. + let coords = vec2(floor(frag_coord.xy)) % 4u; + let threshold = i32((DITHER_THRESHOLD_MAP[coords.y] >> (coords.x * 8)) & 0xff); + if ((dither >= 0 && dither + threshold >= 16) || (dither < 0 && 1 + dither + threshold <= 0)) { + discard; + } +} +#endif + +fn alpha_discard(material: pbr_types::StandardMaterial, output_color: vec4) -> vec4 { + var color = output_color; + let alpha_mode = material.flags & pbr_types::STANDARD_MATERIAL_FLAGS_ALPHA_MODE_RESERVED_BITS; + if alpha_mode == pbr_types::STANDARD_MATERIAL_FLAGS_ALPHA_MODE_OPAQUE { + // NOTE: If rendering as opaque, alpha should be ignored so set to 1.0 + color.a = 1.0; + } + +#ifdef MAY_DISCARD + // NOTE: `MAY_DISCARD` is only defined in the alpha to coverage case if MSAA + // was off. This special situation causes alpha to coverage to fall back to + // alpha mask. + else if alpha_mode == pbr_types::STANDARD_MATERIAL_FLAGS_ALPHA_MODE_MASK || + alpha_mode == pbr_types::STANDARD_MATERIAL_FLAGS_ALPHA_MODE_ALPHA_TO_COVERAGE { + if color.a >= material.alpha_cutoff { + // NOTE: If rendering as masked alpha and >= the cutoff, render as fully opaque + color.a = 1.0; + } else { + // NOTE: output_color.a < in.material.alpha_cutoff should not be rendered + discard; + } + } +#endif + + return color; +} + +fn prepare_world_normal( + world_normal: vec3, + double_sided: bool, + is_front: bool, +) -> vec3 { + var output: vec3 = world_normal; +#ifndef VERTEX_TANGENTS +#ifndef STANDARD_MATERIAL_NORMAL_MAP + // NOTE: When NOT using normal-mapping, if looking at the back face of a double-sided + // material, the normal needs to be inverted. This is a branchless version of that. + output = (f32(!double_sided || is_front) * 2.0 - 1.0) * output; +#endif +#endif + return output; +} + +// Calculates the three TBN vectors according to [mikktspace]. Returns a matrix +// with T, B, N columns in that order. +// +// [mikktspace]: http://www.mikktspace.com/ +fn calculate_tbn_mikktspace(world_normal: vec3, world_tangent: vec4) -> mat3x3 { + // NOTE: The mikktspace method of normal mapping explicitly requires that the world normal NOT + // be re-normalized in the fragment shader. This is primarily to match the way mikktspace + // bakes vertex tangents and normal maps so that this is the exact inverse. Blender, Unity, + // Unreal Engine, Godot, and more all use the mikktspace method. Do not change this code + // unless you really know what you are doing. + // http://www.mikktspace.com/ + var N: vec3 = world_normal; + + // NOTE: The mikktspace method of normal mapping explicitly requires that these NOT be + // normalized nor any Gram-Schmidt applied to ensure the vertex normal is orthogonal to the + // vertex tangent! Do not change this code unless you really know what you are doing. + // http://www.mikktspace.com/ + var T: vec3 = world_tangent.xyz; + var B: vec3 = world_tangent.w * cross(N, T); + +#ifdef MESHLET_MESH_MATERIAL_PASS + // https://www.jeremyong.com/graphics/2023/12/16/surface-gradient-bump-mapping/#a-note-on-mikktspace-usage + let inverse_length_n = 1.0 / length(N); + T *= inverse_length_n; + B *= inverse_length_n; + N *= inverse_length_n; +#endif + + return mat3x3(T, B, N); +} + +fn apply_normal_mapping( + standard_material_flags: u32, + TBN: mat3x3, + double_sided: bool, + is_front: bool, + in_Nt: vec3, +) -> vec3 { + // Unpack the TBN vectors. + var T = TBN[0]; + var B = TBN[1]; + var N = TBN[2]; + + // Nt is the tangent-space normal. + var Nt = in_Nt; + if (standard_material_flags & pbr_types::STANDARD_MATERIAL_FLAGS_TWO_COMPONENT_NORMAL_MAP) != 0u { + // Only use the xy components and derive z for 2-component normal maps. + Nt = vec3(Nt.rg * 2.0 - 1.0, 0.0); + Nt.z = sqrt(1.0 - Nt.x * Nt.x - Nt.y * Nt.y); + } else { + Nt = Nt * 2.0 - 1.0; + } + // Normal maps authored for DirectX require flipping the y component + if (standard_material_flags & pbr_types::STANDARD_MATERIAL_FLAGS_FLIP_NORMAL_MAP_Y) != 0u { + Nt.y = -Nt.y; + } + + if double_sided && !is_front { + Nt = -Nt; + } + + // NOTE: The mikktspace method of normal mapping applies maps the tangent-space normal from + // the normal map texture in this way to be an EXACT inverse of how the normal map baker + // calculates the normal maps so there is no error introduced. Do not change this code + // unless you really know what you are doing. + // http://www.mikktspace.com/ + N = Nt.x * T + Nt.y * B + Nt.z * N; + + return normalize(N); +} + +#ifdef STANDARD_MATERIAL_ANISOTROPY + +// Modifies the normal to achieve a better approximate direction from the +// environment map when using anisotropy. +// +// This follows the suggested implementation in the `KHR_materials_anisotropy` specification: +// https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_materials_anisotropy/README.md#image-based-lighting +fn bend_normal_for_anisotropy(lighting_input: ptr) { + // Unpack. + let N = (*lighting_input).layers[LAYER_BASE].N; + let roughness = (*lighting_input).layers[LAYER_BASE].roughness; + let V = (*lighting_input).V; + let anisotropy = (*lighting_input).anisotropy; + let Ba = (*lighting_input).Ba; + + var bent_normal = normalize(cross(cross(Ba, V), Ba)); + + // The `KHR_materials_anisotropy` spec states: + // + // > This heuristic can probably be improved upon + let a = pow(2.0, pow(2.0, 1.0 - anisotropy * (1.0 - roughness))); + bent_normal = normalize(mix(bent_normal, N, a)); + + // The `KHR_materials_anisotropy` spec states: + // + // > Mixing the reflection with the normal is more accurate both with and + // > without anisotropy and keeps rough objects from gathering light from + // > behind their tangent plane. + let R = normalize(mix(reflect(-V, bent_normal), bent_normal, roughness * roughness)); + + (*lighting_input).layers[LAYER_BASE].N = bent_normal; + (*lighting_input).layers[LAYER_BASE].R = R; +} + +#endif // STANDARD_MATERIAL_ANISOTROPY + +// NOTE: Correctly calculates the view vector depending on whether +// the projection is orthographic or perspective. +fn calculate_view( + world_position: vec4, + is_orthographic: bool, +) -> vec3 { + var V: vec3; + if is_orthographic { + // Orthographic view vector + V = normalize(vec3(view_bindings::view.clip_from_world[0].z, view_bindings::view.clip_from_world[1].z, view_bindings::view.clip_from_world[2].z)); + } else { + // Only valid for a perspective projection + V = normalize(view_bindings::view.world_position.xyz - world_position.xyz); + } + return V; +} + +// Diffuse strength is inversely related to metallicity, specular and diffuse transmission +fn calculate_diffuse_color( + base_color: vec3, + metallic: f32, + specular_transmission: f32, + diffuse_transmission: f32 +) -> vec3 { + return base_color * (1.0 - metallic) * (1.0 - specular_transmission) * + (1.0 - diffuse_transmission); +} + +// Remapping [0,1] reflectance to F0 +// See https://google.github.io/filament/Filament.html#materialsystem/parameterization/remapping +fn calculate_F0(base_color: vec3, metallic: f32, reflectance: vec3) -> vec3 { + return 0.16 * reflectance * reflectance * (1.0 - metallic) + base_color * metallic; +} + +#ifndef PREPASS_FRAGMENT +fn apply_pbr_lighting( + in: pbr_types::PbrInput, +) -> vec4 { + var output_color: vec4 = in.material.base_color; + + let emissive = in.material.emissive; + + // calculate non-linear roughness from linear perceptualRoughness + let metallic = in.material.metallic; + let perceptual_roughness = in.material.perceptual_roughness; + let roughness = lighting::perceptualRoughnessToRoughness(perceptual_roughness); + let ior = in.material.ior; + let thickness = in.material.thickness; + let reflectance = in.material.reflectance; + let diffuse_transmission = in.material.diffuse_transmission; + let specular_transmission = in.material.specular_transmission; + + let specular_transmissive_color = specular_transmission * in.material.base_color.rgb; + + let diffuse_occlusion = in.diffuse_occlusion; + let specular_occlusion = in.specular_occlusion; + + // Neubelt and Pettineo 2013, "Crafting a Next-gen Material Pipeline for The Order: 1886" + let NdotV = max(dot(in.N, in.V), 0.0001); + let R = reflect(-in.V, in.N); + +#ifdef STANDARD_MATERIAL_CLEARCOAT + // Do the above calculations again for the clearcoat layer. Remember that + // the clearcoat can have its own roughness and its own normal. + let clearcoat = in.material.clearcoat; + let clearcoat_perceptual_roughness = in.material.clearcoat_perceptual_roughness; + let clearcoat_roughness = lighting::perceptualRoughnessToRoughness(clearcoat_perceptual_roughness); + let clearcoat_N = in.clearcoat_N; + let clearcoat_NdotV = max(dot(clearcoat_N, in.V), 0.0001); + let clearcoat_R = reflect(-in.V, clearcoat_N); +#endif // STANDARD_MATERIAL_CLEARCOAT + + let diffuse_color = calculate_diffuse_color( + output_color.rgb, + metallic, + specular_transmission, + diffuse_transmission + ); + + // Diffuse transmissive strength is inversely related to metallicity and specular transmission, but directly related to diffuse transmission + let diffuse_transmissive_color = output_color.rgb * (1.0 - metallic) * (1.0 - specular_transmission) * diffuse_transmission; + + // Calculate the world position of the second Lambertian lobe used for diffuse transmission, by subtracting material thickness + let diffuse_transmissive_lobe_world_position = in.world_position - vec4(in.world_normal, 0.0) * thickness; + + let F0 = calculate_F0(output_color.rgb, metallic, reflectance); + let F_ab = lighting::F_AB(perceptual_roughness, NdotV); + + var direct_light: vec3 = vec3(0.0); + + // Transmitted Light (Specular and Diffuse) + var transmitted_light: vec3 = vec3(0.0); + + // Pack all the values into a structure. + var lighting_input: lighting::LightingInput; + lighting_input.layers[LAYER_BASE].NdotV = NdotV; + lighting_input.layers[LAYER_BASE].N = in.N; + lighting_input.layers[LAYER_BASE].R = R; + lighting_input.layers[LAYER_BASE].perceptual_roughness = perceptual_roughness; + lighting_input.layers[LAYER_BASE].roughness = roughness; + lighting_input.P = in.world_position.xyz; + lighting_input.V = in.V; + lighting_input.diffuse_color = diffuse_color; + lighting_input.F0_ = F0; + lighting_input.F_ab = F_ab; +#ifdef STANDARD_MATERIAL_CLEARCOAT + lighting_input.layers[LAYER_CLEARCOAT].NdotV = clearcoat_NdotV; + lighting_input.layers[LAYER_CLEARCOAT].N = clearcoat_N; + lighting_input.layers[LAYER_CLEARCOAT].R = clearcoat_R; + lighting_input.layers[LAYER_CLEARCOAT].perceptual_roughness = clearcoat_perceptual_roughness; + lighting_input.layers[LAYER_CLEARCOAT].roughness = clearcoat_roughness; + lighting_input.clearcoat_strength = clearcoat; +#endif // STANDARD_MATERIAL_CLEARCOAT +#ifdef STANDARD_MATERIAL_ANISOTROPY + lighting_input.anisotropy = in.anisotropy_strength; + lighting_input.Ta = in.anisotropy_T; + lighting_input.Ba = in.anisotropy_B; +#endif // STANDARD_MATERIAL_ANISOTROPY + + // And do the same for transmissive if we need to. +#ifdef STANDARD_MATERIAL_DIFFUSE_TRANSMISSION + var transmissive_lighting_input: lighting::LightingInput; + transmissive_lighting_input.layers[LAYER_BASE].NdotV = 1.0; + transmissive_lighting_input.layers[LAYER_BASE].N = -in.N; + transmissive_lighting_input.layers[LAYER_BASE].R = vec3(0.0); + transmissive_lighting_input.layers[LAYER_BASE].perceptual_roughness = 1.0; + transmissive_lighting_input.layers[LAYER_BASE].roughness = 1.0; + transmissive_lighting_input.P = diffuse_transmissive_lobe_world_position.xyz; + transmissive_lighting_input.V = -in.V; + transmissive_lighting_input.diffuse_color = diffuse_transmissive_color; + transmissive_lighting_input.F0_ = vec3(0.0); + transmissive_lighting_input.F_ab = vec2(0.1); +#ifdef STANDARD_MATERIAL_CLEARCOAT + transmissive_lighting_input.layers[LAYER_CLEARCOAT].NdotV = 0.0; + transmissive_lighting_input.layers[LAYER_CLEARCOAT].N = vec3(0.0); + transmissive_lighting_input.layers[LAYER_CLEARCOAT].R = vec3(0.0); + transmissive_lighting_input.layers[LAYER_CLEARCOAT].perceptual_roughness = 0.0; + transmissive_lighting_input.layers[LAYER_CLEARCOAT].roughness = 0.0; + transmissive_lighting_input.clearcoat_strength = 0.0; +#endif // STANDARD_MATERIAL_CLEARCOAT +#ifdef STANDARD_MATERIAL_ANISOTROPY + transmissive_lighting_input.anisotropy = in.anisotropy_strength; + transmissive_lighting_input.Ta = in.anisotropy_T; + transmissive_lighting_input.Ba = in.anisotropy_B; +#endif // STANDARD_MATERIAL_ANISOTROPY +#endif // STANDARD_MATERIAL_DIFFUSE_TRANSMISSION + + let view_z = dot(vec4( + view_bindings::view.view_from_world[0].z, + view_bindings::view.view_from_world[1].z, + view_bindings::view.view_from_world[2].z, + view_bindings::view.view_from_world[3].z + ), in.world_position); + let cluster_index = clustering::fragment_cluster_index(in.frag_coord.xy, view_z, in.is_orthographic); + var clusterable_object_index_ranges = + clustering::unpack_clusterable_object_index_ranges(cluster_index); + + // Point lights (direct) + for (var i: u32 = clusterable_object_index_ranges.first_point_light_index_offset; + i < clusterable_object_index_ranges.first_spot_light_index_offset; + i = i + 1u) { + let light_id = clustering::get_clusterable_object_id(i); + + // If we're lightmapped, disable diffuse contribution from the light if + // requested, to avoid double-counting light. +#ifdef LIGHTMAP + let enable_diffuse = + (view_bindings::clusterable_objects.data[light_id].flags & + mesh_view_types::POINT_LIGHT_FLAGS_AFFECTS_LIGHTMAPPED_MESH_DIFFUSE_BIT) != 0u; +#else // LIGHTMAP + let enable_diffuse = true; +#endif // LIGHTMAP + + var shadow: f32 = 1.0; + if ((in.flags & MESH_FLAGS_SHADOW_RECEIVER_BIT) != 0u + && (view_bindings::clusterable_objects.data[light_id].flags & mesh_view_types::POINT_LIGHT_FLAGS_SHADOWS_ENABLED_BIT) != 0u) { + shadow = shadows::fetch_point_shadow(light_id, in.world_position, in.world_normal); + } + + let light_contrib = lighting::point_light(light_id, &lighting_input, enable_diffuse); + direct_light += light_contrib * shadow; + +#ifdef STANDARD_MATERIAL_DIFFUSE_TRANSMISSION + // NOTE: We use the diffuse transmissive color, the second Lambertian lobe's calculated + // world position, inverted normal and view vectors, and the following simplified + // values for a fully diffuse transmitted light contribution approximation: + // + // roughness = 1.0; + // NdotV = 1.0; + // R = vec3(0.0) // doesn't really matter + // F_ab = vec2(0.1) + // F0 = vec3(0.0) + var transmitted_shadow: f32 = 1.0; + if ((in.flags & (MESH_FLAGS_SHADOW_RECEIVER_BIT | MESH_FLAGS_TRANSMITTED_SHADOW_RECEIVER_BIT)) == (MESH_FLAGS_SHADOW_RECEIVER_BIT | MESH_FLAGS_TRANSMITTED_SHADOW_RECEIVER_BIT) + && (view_bindings::clusterable_objects.data[light_id].flags & mesh_view_types::POINT_LIGHT_FLAGS_SHADOWS_ENABLED_BIT) != 0u) { + transmitted_shadow = shadows::fetch_point_shadow(light_id, diffuse_transmissive_lobe_world_position, -in.world_normal); + } + + let transmitted_light_contrib = + lighting::point_light(light_id, &transmissive_lighting_input, enable_diffuse); + transmitted_light += transmitted_light_contrib * transmitted_shadow; +#endif + } + + // Spot lights (direct) + for (var i: u32 = clusterable_object_index_ranges.first_spot_light_index_offset; + i < clusterable_object_index_ranges.first_reflection_probe_index_offset; + i = i + 1u) { + let light_id = clustering::get_clusterable_object_id(i); + + // If we're lightmapped, disable diffuse contribution from the light if + // requested, to avoid double-counting light. +#ifdef LIGHTMAP + let enable_diffuse = + (view_bindings::clusterable_objects.data[light_id].flags & + mesh_view_types::POINT_LIGHT_FLAGS_AFFECTS_LIGHTMAPPED_MESH_DIFFUSE_BIT) != 0u; +#else // LIGHTMAP + let enable_diffuse = true; +#endif // LIGHTMAP + + var shadow: f32 = 1.0; + if ((in.flags & MESH_FLAGS_SHADOW_RECEIVER_BIT) != 0u + && (view_bindings::clusterable_objects.data[light_id].flags & + mesh_view_types::POINT_LIGHT_FLAGS_SHADOWS_ENABLED_BIT) != 0u) { + shadow = shadows::fetch_spot_shadow( + light_id, + in.world_position, + in.world_normal, + view_bindings::clusterable_objects.data[light_id].shadow_map_near_z, + ); + } + + let light_contrib = lighting::spot_light(light_id, &lighting_input, enable_diffuse); + direct_light += light_contrib * shadow; + +#ifdef STANDARD_MATERIAL_DIFFUSE_TRANSMISSION + // NOTE: We use the diffuse transmissive color, the second Lambertian lobe's calculated + // world position, inverted normal and view vectors, and the following simplified + // values for a fully diffuse transmitted light contribution approximation: + // + // roughness = 1.0; + // NdotV = 1.0; + // R = vec3(0.0) // doesn't really matter + // F_ab = vec2(0.1) + // F0 = vec3(0.0) + var transmitted_shadow: f32 = 1.0; + if ((in.flags & (MESH_FLAGS_SHADOW_RECEIVER_BIT | MESH_FLAGS_TRANSMITTED_SHADOW_RECEIVER_BIT)) == (MESH_FLAGS_SHADOW_RECEIVER_BIT | MESH_FLAGS_TRANSMITTED_SHADOW_RECEIVER_BIT) + && (view_bindings::clusterable_objects.data[light_id].flags & mesh_view_types::POINT_LIGHT_FLAGS_SHADOWS_ENABLED_BIT) != 0u) { + transmitted_shadow = shadows::fetch_spot_shadow( + light_id, + diffuse_transmissive_lobe_world_position, + -in.world_normal, + view_bindings::clusterable_objects.data[light_id].shadow_map_near_z, + ); + } + + let transmitted_light_contrib = + lighting::spot_light(light_id, &transmissive_lighting_input, enable_diffuse); + transmitted_light += transmitted_light_contrib * transmitted_shadow; +#endif + } + + // directional lights (direct) + let n_directional_lights = view_bindings::lights.n_directional_lights; + for (var i: u32 = 0u; i < n_directional_lights; i = i + 1u) { + // check if this light should be skipped, which occurs if this light does not intersect with the view + // note point and spot lights aren't skippable, as the relevant lights are filtered in `assign_lights_to_clusters` + let light = &view_bindings::lights.directional_lights[i]; + if (*light).skip != 0u { + continue; + } + + // If we're lightmapped, disable diffuse contribution from the light if + // requested, to avoid double-counting light. +#ifdef LIGHTMAP + let enable_diffuse = + ((*light).flags & + mesh_view_types::DIRECTIONAL_LIGHT_FLAGS_AFFECTS_LIGHTMAPPED_MESH_DIFFUSE_BIT) != + 0u; +#else // LIGHTMAP + let enable_diffuse = true; +#endif // LIGHTMAP + + var shadow: f32 = 1.0; + if ((in.flags & MESH_FLAGS_SHADOW_RECEIVER_BIT) != 0u + && (view_bindings::lights.directional_lights[i].flags & mesh_view_types::DIRECTIONAL_LIGHT_FLAGS_SHADOWS_ENABLED_BIT) != 0u) { + shadow = shadows::fetch_directional_shadow(i, in.world_position, in.world_normal, view_z); + } + + var light_contrib = lighting::directional_light(i, &lighting_input, enable_diffuse); + +#ifdef DIRECTIONAL_LIGHT_SHADOW_MAP_DEBUG_CASCADES + light_contrib = shadows::cascade_debug_visualization(light_contrib, i, view_z); +#endif + direct_light += light_contrib * shadow; + +#ifdef STANDARD_MATERIAL_DIFFUSE_TRANSMISSION + // NOTE: We use the diffuse transmissive color, the second Lambertian lobe's calculated + // world position, inverted normal and view vectors, and the following simplified + // values for a fully diffuse transmitted light contribution approximation: + // + // roughness = 1.0; + // NdotV = 1.0; + // R = vec3(0.0) // doesn't really matter + // F_ab = vec2(0.1) + // F0 = vec3(0.0) + var transmitted_shadow: f32 = 1.0; + if ((in.flags & (MESH_FLAGS_SHADOW_RECEIVER_BIT | MESH_FLAGS_TRANSMITTED_SHADOW_RECEIVER_BIT)) == (MESH_FLAGS_SHADOW_RECEIVER_BIT | MESH_FLAGS_TRANSMITTED_SHADOW_RECEIVER_BIT) + && (view_bindings::lights.directional_lights[i].flags & mesh_view_types::DIRECTIONAL_LIGHT_FLAGS_SHADOWS_ENABLED_BIT) != 0u) { + transmitted_shadow = shadows::fetch_directional_shadow(i, diffuse_transmissive_lobe_world_position, -in.world_normal, view_z); + } + + let transmitted_light_contrib = + lighting::directional_light(i, &transmissive_lighting_input, enable_diffuse); + transmitted_light += transmitted_light_contrib * transmitted_shadow; +#endif + } + +#ifdef STANDARD_MATERIAL_DIFFUSE_TRANSMISSION + // NOTE: We use the diffuse transmissive color, the second Lambertian lobe's calculated + // world position, inverted normal and view vectors, and the following simplified + // values for a fully diffuse transmitted light contribution approximation: + // + // perceptual_roughness = 1.0; + // NdotV = 1.0; + // F0 = vec3(0.0) + // diffuse_occlusion = vec3(1.0) + transmitted_light += ambient::ambient_light(diffuse_transmissive_lobe_world_position, -in.N, -in.V, 1.0, diffuse_transmissive_color, vec3(0.0), 1.0, vec3(1.0)); +#endif + + // Diffuse indirect lighting can come from a variety of sources. The + // priority goes like this: + // + // 1. Lightmap (highest) + // 2. Irradiance volume + // 3. Environment map (lowest) + // + // When we find a source of diffuse indirect lighting, we stop accumulating + // any more diffuse indirect light. This avoids double-counting if, for + // example, both lightmaps and irradiance volumes are present. + + var indirect_light = vec3(0.0f); + var found_diffuse_indirect = false; + +#ifdef LIGHTMAP + indirect_light += in.lightmap_light * diffuse_color; + found_diffuse_indirect = true; +#endif + +#ifdef IRRADIANCE_VOLUME + // Irradiance volume light (indirect) + if (!found_diffuse_indirect) { + let irradiance_volume_light = irradiance_volume::irradiance_volume_light( + in.world_position.xyz, + in.N, + &clusterable_object_index_ranges, + ); + indirect_light += irradiance_volume_light * diffuse_color * diffuse_occlusion; + found_diffuse_indirect = true; + } +#endif + + // Environment map light (indirect) +#ifdef ENVIRONMENT_MAP + +#ifdef STANDARD_MATERIAL_ANISOTROPY + var bent_normal_lighting_input = lighting_input; + bend_normal_for_anisotropy(&bent_normal_lighting_input); + let environment_map_lighting_input = &bent_normal_lighting_input; +#else // STANDARD_MATERIAL_ANISOTROPY + let environment_map_lighting_input = &lighting_input; +#endif // STANDARD_MATERIAL_ANISOTROPY + + let environment_light = environment_map::environment_map_light( + environment_map_lighting_input, + &clusterable_object_index_ranges, + found_diffuse_indirect, + ); + + // If screen space reflections are going to be used for this material, don't + // accumulate environment map light yet. The SSR shader will do it. +#ifdef SCREEN_SPACE_REFLECTIONS + let use_ssr = perceptual_roughness <= + view_bindings::ssr_settings.perceptual_roughness_threshold; +#else // SCREEN_SPACE_REFLECTIONS + let use_ssr = false; +#endif // SCREEN_SPACE_REFLECTIONS + + if (!use_ssr) { + let environment_light = environment_map::environment_map_light( + &lighting_input, + &clusterable_object_index_ranges, + found_diffuse_indirect + ); + + indirect_light += environment_light.diffuse * diffuse_occlusion + + environment_light.specular * specular_occlusion; + } + +#endif // ENVIRONMENT_MAP + + // Ambient light (indirect) + indirect_light += ambient::ambient_light(in.world_position, in.N, in.V, NdotV, diffuse_color, F0, perceptual_roughness, diffuse_occlusion); + + // we'll use the specular component of the transmitted environment + // light in the call to `specular_transmissive_light()` below + var specular_transmitted_environment_light = vec3(0.0); + +#ifdef ENVIRONMENT_MAP + +#ifdef STANDARD_MATERIAL_DIFFUSE_OR_SPECULAR_TRANSMISSION + // NOTE: We use the diffuse transmissive color, inverted normal and view vectors, + // and the following simplified values for the transmitted environment light contribution + // approximation: + // + // diffuse_color = vec3(1.0) // later we use `diffuse_transmissive_color` and `specular_transmissive_color` + // NdotV = 1.0; + // R = T // see definition below + // F0 = vec3(1.0) + // diffuse_occlusion = 1.0 + // + // (This one is slightly different from the other light types above, because the environment + // map light returns both diffuse and specular components separately, and we want to use both) + + let T = -normalize( + in.V + // start with view vector at entry point + refract(in.V, -in.N, 1.0 / ior) * thickness // add refracted vector scaled by thickness, towards exit point + ); // normalize to find exit point view vector + + var transmissive_environment_light_input: lighting::LightingInput; + transmissive_environment_light_input.diffuse_color = vec3(1.0); + transmissive_environment_light_input.layers[LAYER_BASE].NdotV = 1.0; + transmissive_environment_light_input.P = in.world_position.xyz; + transmissive_environment_light_input.layers[LAYER_BASE].N = -in.N; + transmissive_environment_light_input.V = in.V; + transmissive_environment_light_input.layers[LAYER_BASE].R = T; + transmissive_environment_light_input.layers[LAYER_BASE].perceptual_roughness = perceptual_roughness; + transmissive_environment_light_input.layers[LAYER_BASE].roughness = roughness; + transmissive_environment_light_input.F0_ = vec3(1.0); + transmissive_environment_light_input.F_ab = vec2(0.1); +#ifdef STANDARD_MATERIAL_CLEARCOAT + // No clearcoat. + transmissive_environment_light_input.clearcoat_strength = 0.0; + transmissive_environment_light_input.layers[LAYER_CLEARCOAT].NdotV = 0.0; + transmissive_environment_light_input.layers[LAYER_CLEARCOAT].N = in.N; + transmissive_environment_light_input.layers[LAYER_CLEARCOAT].R = vec3(0.0); + transmissive_environment_light_input.layers[LAYER_CLEARCOAT].perceptual_roughness = 0.0; + transmissive_environment_light_input.layers[LAYER_CLEARCOAT].roughness = 0.0; +#endif // STANDARD_MATERIAL_CLEARCOAT + + let transmitted_environment_light = environment_map::environment_map_light( + &transmissive_environment_light_input, + &clusterable_object_index_ranges, + false, + ); + +#ifdef STANDARD_MATERIAL_DIFFUSE_TRANSMISSION + transmitted_light += transmitted_environment_light.diffuse * diffuse_transmissive_color; +#endif // STANDARD_MATERIAL_DIFFUSE_TRANSMISSION +#ifdef STANDARD_MATERIAL_SPECULAR_TRANSMISSION + specular_transmitted_environment_light = transmitted_environment_light.specular * specular_transmissive_color; +#endif // STANDARD_MATERIAL_SPECULAR_TRANSMISSION + +#endif // STANDARD_MATERIAL_SPECULAR_OR_DIFFUSE_TRANSMISSION + +#endif // ENVIRONMENT_MAP + + var emissive_light = emissive.rgb * output_color.a; + + // "The clearcoat layer is on top of emission in the layering stack. + // Consequently, the emission is darkened by the Fresnel term." + // + // +#ifdef STANDARD_MATERIAL_CLEARCOAT + emissive_light = emissive_light * (0.04 + (1.0 - 0.04) * pow(1.0 - clearcoat_NdotV, 5.0)); +#endif + + emissive_light = emissive_light * mix(1.0, view_bindings::view.exposure, emissive.a); + +#ifdef STANDARD_MATERIAL_SPECULAR_TRANSMISSION + transmitted_light += transmission::specular_transmissive_light(in.world_position, in.frag_coord.xyz, view_z, in.N, in.V, F0, ior, thickness, perceptual_roughness, specular_transmissive_color, specular_transmitted_environment_light).rgb; + + if (in.material.flags & pbr_types::STANDARD_MATERIAL_FLAGS_ATTENUATION_ENABLED_BIT) != 0u { + // We reuse the `atmospheric_fog()` function here, as it's fundamentally + // equivalent to the attenuation that takes place inside the material volume, + // and will allow us to eventually hook up subsurface scattering more easily + var attenuation_fog: mesh_view_types::Fog; + attenuation_fog.base_color.a = 1.0; + attenuation_fog.be = pow(1.0 - in.material.attenuation_color.rgb, vec3(E)) / in.material.attenuation_distance; + // TODO: Add the subsurface scattering factor below + // attenuation_fog.bi = /* ... */ + transmitted_light = bevy_pbr::fog::atmospheric_fog( + attenuation_fog, vec4(transmitted_light, 1.0), thickness, + vec3(0.0) // TODO: Pass in (pre-attenuated) scattered light contribution here + ).rgb; + } +#endif + + // Total light + output_color = vec4( + (view_bindings::view.exposure * (transmitted_light + direct_light + indirect_light)) + emissive_light, + output_color.a + ); + + output_color = clustering::cluster_debug_visualization( + output_color, + view_z, + in.is_orthographic, + clusterable_object_index_ranges, + cluster_index, + ); + + return output_color; +} +#endif // PREPASS_FRAGMENT + +#ifdef DISTANCE_FOG +fn apply_fog(fog_params: mesh_view_types::Fog, input_color: vec4, fragment_world_position: vec3, view_world_position: vec3) -> vec4 { + let view_to_world = fragment_world_position.xyz - view_world_position.xyz; + + // `length()` is used here instead of just `view_to_world.z` since that produces more + // high quality results, especially for denser/smaller fogs. we get a "curved" + // fog shape that remains consistent with camera rotation, instead of a "linear" + // fog shape that looks a bit fake + let distance = length(view_to_world); + + var scattering = vec3(0.0); + if fog_params.directional_light_color.a > 0.0 { + let view_to_world_normalized = view_to_world / distance; + let n_directional_lights = view_bindings::lights.n_directional_lights; + for (var i: u32 = 0u; i < n_directional_lights; i = i + 1u) { + let light = view_bindings::lights.directional_lights[i]; + scattering += pow( + max( + dot(view_to_world_normalized, light.direction_to_light), + 0.0 + ), + fog_params.directional_light_exponent + ) * light.color.rgb * view_bindings::view.exposure; + } + } + + if fog_params.mode == mesh_view_types::FOG_MODE_LINEAR { + return bevy_pbr::fog::linear_fog(fog_params, input_color, distance, scattering); + } else if fog_params.mode == mesh_view_types::FOG_MODE_EXPONENTIAL { + return bevy_pbr::fog::exponential_fog(fog_params, input_color, distance, scattering); + } else if fog_params.mode == mesh_view_types::FOG_MODE_EXPONENTIAL_SQUARED { + return bevy_pbr::fog::exponential_squared_fog(fog_params, input_color, distance, scattering); + } else if fog_params.mode == mesh_view_types::FOG_MODE_ATMOSPHERIC { + return bevy_pbr::fog::atmospheric_fog(fog_params, input_color, distance, scattering); + } else { + return input_color; + } +} +#endif // DISTANCE_FOG + +#ifdef PREMULTIPLY_ALPHA +fn premultiply_alpha(standard_material_flags: u32, color: vec4) -> vec4 { +// `Blend`, `Premultiplied` and `Alpha` all share the same `BlendState`. Depending +// on the alpha mode, we premultiply the color channels by the alpha channel value, +// (and also optionally replace the alpha value with 0.0) so that the result produces +// the desired blend mode when sent to the blending operation. +#ifdef BLEND_PREMULTIPLIED_ALPHA + // For `BlendState::PREMULTIPLIED_ALPHA_BLENDING` the blend function is: + // + // result = 1 * src_color + (1 - src_alpha) * dst_color + let alpha_mode = standard_material_flags & pbr_types::STANDARD_MATERIAL_FLAGS_ALPHA_MODE_RESERVED_BITS; + if alpha_mode == pbr_types::STANDARD_MATERIAL_FLAGS_ALPHA_MODE_ADD { + // Here, we premultiply `src_color` by `src_alpha`, and replace `src_alpha` with 0.0: + // + // src_color *= src_alpha + // src_alpha = 0.0 + // + // We end up with: + // + // result = 1 * (src_alpha * src_color) + (1 - 0) * dst_color + // result = src_alpha * src_color + 1 * dst_color + // + // Which is the blend operation for additive blending + return vec4(color.rgb * color.a, 0.0); + } else { + // Here, we don't do anything, so that we get premultiplied alpha blending. (As expected) + return color.rgba; + } +#endif +// `Multiply` uses its own `BlendState`, but we still need to premultiply here in the +// shader so that we get correct results as we tweak the alpha channel +#ifdef BLEND_MULTIPLY + // The blend function is: + // + // result = dst_color * src_color + (1 - src_alpha) * dst_color + // + // We premultiply `src_color` by `src_alpha`: + // + // src_color *= src_alpha + // + // We end up with: + // + // result = dst_color * (src_color * src_alpha) + (1 - src_alpha) * dst_color + // result = src_alpha * (src_color * dst_color) + (1 - src_alpha) * dst_color + // + // Which is the blend operation for multiplicative blending with arbitrary mixing + // controlled by the source alpha channel + return vec4(color.rgb * color.a, color.a); +#endif +} +#endif + +// fog, alpha premultiply +// for non-hdr cameras, tonemapping and debanding +fn main_pass_post_lighting_processing( + pbr_input: pbr_types::PbrInput, + input_color: vec4, +) -> vec4 { + var output_color = input_color; + +#ifdef DISTANCE_FOG + // fog + if ((pbr_input.material.flags & pbr_types::STANDARD_MATERIAL_FLAGS_FOG_ENABLED_BIT) != 0u) { + output_color = apply_fog(view_bindings::fog, output_color, pbr_input.world_position.xyz, view_bindings::view.world_position.xyz); + } +#endif // DISTANCE_FOG + +#ifdef TONEMAP_IN_SHADER + output_color = tone_mapping(output_color, view_bindings::view.color_grading); +#ifdef DEBAND_DITHER + var output_rgb = output_color.rgb; + output_rgb = powsafe(output_rgb, 1.0 / 2.2); + output_rgb += screen_space_dither(pbr_input.frag_coord.xy); + // This conversion back to linear space is required because our output texture format is + // SRGB; the GPU will assume our output is linear and will apply an SRGB conversion. + output_rgb = powsafe(output_rgb, 2.2); + output_color = vec4(output_rgb, output_color.a); +#endif +#endif +#ifdef PREMULTIPLY_ALPHA + output_color = premultiply_alpha(pbr_input.material.flags, output_color); +#endif + return output_color; +} diff --git a/crates/bevy_pbr/src/render/pbr_lighting.wgsl b/crates/bevy_render_3d/src/render/pbr_lighting.wgsl similarity index 100% rename from crates/bevy_pbr/src/render/pbr_lighting.wgsl rename to crates/bevy_render_3d/src/render/pbr_lighting.wgsl diff --git a/crates/bevy_render_3d/src/render/pbr_prepass.wgsl b/crates/bevy_render_3d/src/render/pbr_prepass.wgsl new file mode 100644 index 0000000000000..68c360248cbd6 --- /dev/null +++ b/crates/bevy_render_3d/src/render/pbr_prepass.wgsl @@ -0,0 +1,151 @@ +#import bevy_pbr::{ + pbr_prepass_functions, + pbr_bindings, + pbr_bindings::material, + pbr_types, + pbr_functions, + pbr_functions::SampleBias, + prepass_io, + mesh_bindings::mesh, + mesh_view_bindings::view, +} + +#import bevy_render::bindless::{bindless_samplers_filtering, bindless_textures_2d} + +#ifdef MESHLET_MESH_MATERIAL_PASS +#import bevy_pbr::meshlet_visibility_buffer_resolve::resolve_vertex_output +#endif + +#ifdef BINDLESS +#import bevy_pbr::pbr_bindings::material_indices +#endif // BINDLESS + +#ifdef PREPASS_FRAGMENT +@fragment +fn fragment( +#ifdef MESHLET_MESH_MATERIAL_PASS + @builtin(position) frag_coord: vec4, +#else + in: prepass_io::VertexOutput, + @builtin(front_facing) is_front: bool, +#endif +) -> prepass_io::FragmentOutput { +#ifdef MESHLET_MESH_MATERIAL_PASS + let in = resolve_vertex_output(frag_coord); + let is_front = true; +#else // MESHLET_MESH_MATERIAL_PASS + +#ifdef BINDLESS + let slot = mesh[in.instance_index].material_and_lightmap_bind_group_slot & 0xffffu; + let flags = pbr_bindings::material_array[material_indices[slot].material].flags; + let uv_transform = pbr_bindings::material_array[material_indices[slot].material].uv_transform; +#else // BINDLESS + let flags = pbr_bindings::material.flags; + let uv_transform = pbr_bindings::material.uv_transform; +#endif // BINDLESS + + // If we're in the crossfade section of a visibility range, conditionally + // discard the fragment according to the visibility pattern. +#ifdef VISIBILITY_RANGE_DITHER + pbr_functions::visibility_range_dither(in.position, in.visibility_range_dither); +#endif // VISIBILITY_RANGE_DITHER + + pbr_prepass_functions::prepass_alpha_discard(in); +#endif // MESHLET_MESH_MATERIAL_PASS + + var out: prepass_io::FragmentOutput; + +#ifdef UNCLIPPED_DEPTH_ORTHO_EMULATION + out.frag_depth = in.unclipped_depth; +#endif // UNCLIPPED_DEPTH_ORTHO_EMULATION + +#ifdef NORMAL_PREPASS + // NOTE: Unlit bit not set means == 0 is true, so the true case is if lit + if (flags & pbr_types::STANDARD_MATERIAL_FLAGS_UNLIT_BIT) == 0u { + let double_sided = (flags & pbr_types::STANDARD_MATERIAL_FLAGS_DOUBLE_SIDED_BIT) != 0u; + + let world_normal = pbr_functions::prepare_world_normal( + in.world_normal, + double_sided, + is_front, + ); + + var normal = world_normal; + +#ifdef VERTEX_UVS +#ifdef VERTEX_TANGENTS +#ifdef STANDARD_MATERIAL_NORMAL_MAP + +// TODO: Transforming UVs mean we need to apply derivative chain rule for meshlet mesh material pass +#ifdef STANDARD_MATERIAL_NORMAL_MAP_UV_B + let uv = (uv_transform * vec3(in.uv_b, 1.0)).xy; +#else + let uv = (uv_transform * vec3(in.uv, 1.0)).xy; +#endif + + // Fill in the sample bias so we can sample from textures. + var bias: SampleBias; +#ifdef MESHLET_MESH_MATERIAL_PASS + bias.ddx_uv = in.ddx_uv; + bias.ddy_uv = in.ddy_uv; +#else // MESHLET_MESH_MATERIAL_PASS + bias.mip_bias = view.mip_bias; +#endif // MESHLET_MESH_MATERIAL_PASS + + let Nt = +#ifdef MESHLET_MESH_MATERIAL_PASS + textureSampleGrad( +#else // MESHLET_MESH_MATERIAL_PASS + textureSampleBias( +#endif // MESHLET_MESH_MATERIAL_PASS +#ifdef BINDLESS + bindless_textures_2d[material_indices[slot].normal_map_texture], + bindless_samplers_filtering[material_indices[slot].normal_map_sampler], +#else // BINDLESS + pbr_bindings::normal_map_texture, + pbr_bindings::normal_map_sampler, +#endif // BINDLESS + uv, +#ifdef MESHLET_MESH_MATERIAL_PASS + bias.ddx_uv, + bias.ddy_uv, +#else // MESHLET_MESH_MATERIAL_PASS + bias.mip_bias, +#endif // MESHLET_MESH_MATERIAL_PASS + ).rgb; + let TBN = pbr_functions::calculate_tbn_mikktspace(normal, in.world_tangent); + + normal = pbr_functions::apply_normal_mapping( + flags, + TBN, + double_sided, + is_front, + Nt, + ); + +#endif // STANDARD_MATERIAL_NORMAL_MAP +#endif // VERTEX_TANGENTS +#endif // VERTEX_UVS + + out.normal = vec4(normal * 0.5 + vec3(0.5), 1.0); + } else { + out.normal = vec4(in.world_normal * 0.5 + vec3(0.5), 1.0); + } +#endif // NORMAL_PREPASS + +#ifdef MOTION_VECTOR_PREPASS +#ifdef MESHLET_MESH_MATERIAL_PASS + out.motion_vector = in.motion_vector; +#else + out.motion_vector = pbr_prepass_functions::calculate_motion_vector(in.world_position, in.previous_world_position); +#endif +#endif + + return out; +} +#else +@fragment +fn fragment(in: prepass_io::VertexOutput) { + pbr_prepass_functions::prepass_alpha_discard(in); +} +#endif // PREPASS_FRAGMENT diff --git a/crates/bevy_render_3d/src/render/pbr_prepass_functions.wgsl b/crates/bevy_render_3d/src/render/pbr_prepass_functions.wgsl new file mode 100644 index 0000000000000..d2d2c71e644a7 --- /dev/null +++ b/crates/bevy_render_3d/src/render/pbr_prepass_functions.wgsl @@ -0,0 +1,102 @@ +#define_import_path bevy_pbr::pbr_prepass_functions + +#import bevy_render::bindless::{bindless_samplers_filtering, bindless_textures_2d} + +#import bevy_pbr::{ + prepass_io::VertexOutput, + prepass_bindings::previous_view_uniforms, + mesh_bindings::mesh, + mesh_view_bindings::view, + pbr_bindings, + pbr_types, +} + +#ifdef BINDLESS +#import bevy_pbr::pbr_bindings::material_indices +#endif // BINDLESS + +// Cutoff used for the premultiplied alpha modes BLEND, ADD, and ALPHA_TO_COVERAGE. +const PREMULTIPLIED_ALPHA_CUTOFF = 0.05; + +// We can use a simplified version of alpha_discard() here since we only need to handle the alpha_cutoff +fn prepass_alpha_discard(in: VertexOutput) { + +#ifdef MAY_DISCARD +#ifdef BINDLESS + let slot = mesh[in.instance_index].material_and_lightmap_bind_group_slot & 0xffffu; + var output_color: vec4 = pbr_bindings::material_array[material_indices[slot].material].base_color; + let flags = pbr_bindings::material_array[material_indices[slot].material].flags; +#else // BINDLESS + var output_color: vec4 = pbr_bindings::material.base_color; + let flags = pbr_bindings::material.flags; +#endif // BINDLESS + +#ifdef VERTEX_UVS +#ifdef STANDARD_MATERIAL_BASE_COLOR_UV_B + var uv = in.uv_b; +#else // STANDARD_MATERIAL_BASE_COLOR_UV_B + var uv = in.uv; +#endif // STANDARD_MATERIAL_BASE_COLOR_UV_B + +#ifdef BINDLESS + let uv_transform = pbr_bindings::material_array[material_indices[slot].material].uv_transform; +#else // BINDLESS + let uv_transform = pbr_bindings::material.uv_transform; +#endif // BINDLESS + + uv = (uv_transform * vec3(uv, 1.0)).xy; + if (flags & pbr_types::STANDARD_MATERIAL_FLAGS_BASE_COLOR_TEXTURE_BIT) != 0u { + output_color = output_color * textureSampleBias( +#ifdef BINDLESS + bindless_textures_2d[material_indices[slot].base_color_texture], + bindless_samplers_filtering[material_indices[slot].base_color_sampler], +#else // BINDLESS + pbr_bindings::base_color_texture, + pbr_bindings::base_color_sampler, +#endif // BINDLESS + uv, + view.mip_bias + ); + } +#endif // VERTEX_UVS + + let alpha_mode = flags & pbr_types::STANDARD_MATERIAL_FLAGS_ALPHA_MODE_RESERVED_BITS; + if alpha_mode == pbr_types::STANDARD_MATERIAL_FLAGS_ALPHA_MODE_MASK { +#ifdef BINDLESS + let alpha_cutoff = pbr_bindings::material_array[material_indices[slot].material].alpha_cutoff; +#else // BINDLESS + let alpha_cutoff = pbr_bindings::material.alpha_cutoff; +#endif // BINDLESS + if output_color.a < alpha_cutoff { + discard; + } + } else if (alpha_mode == pbr_types::STANDARD_MATERIAL_FLAGS_ALPHA_MODE_BLEND || + alpha_mode == pbr_types::STANDARD_MATERIAL_FLAGS_ALPHA_MODE_ADD || + alpha_mode == pbr_types::STANDARD_MATERIAL_FLAGS_ALPHA_MODE_ALPHA_TO_COVERAGE) { + if output_color.a < PREMULTIPLIED_ALPHA_CUTOFF { + discard; + } + } else if alpha_mode == pbr_types::STANDARD_MATERIAL_FLAGS_ALPHA_MODE_PREMULTIPLIED { + if all(output_color < vec4(PREMULTIPLIED_ALPHA_CUTOFF)) { + discard; + } + } + +#endif // MAY_DISCARD +} + +#ifdef MOTION_VECTOR_PREPASS +fn calculate_motion_vector(world_position: vec4, previous_world_position: vec4) -> vec2 { + let clip_position_t = view.unjittered_clip_from_world * world_position; + let clip_position = clip_position_t.xy / clip_position_t.w; + let previous_clip_position_t = previous_view_uniforms.clip_from_world * previous_world_position; + let previous_clip_position = previous_clip_position_t.xy / previous_clip_position_t.w; + // These motion vectors are used as offsets to UV positions and are stored + // in the range -1,1 to allow offsetting from the one corner to the + // diagonally-opposite corner in UV coordinates, in either direction. + // A difference between diagonally-opposite corners of clip space is in the + // range -2,2, so this needs to be scaled by 0.5. And the V direction goes + // down where clip space y goes up, so y needs to be flipped. + return (clip_position - previous_clip_position) * vec2(0.5, -0.5); +} +#endif // MOTION_VECTOR_PREPASS diff --git a/crates/bevy_pbr/src/render/pbr_transmission.wgsl b/crates/bevy_render_3d/src/render/pbr_transmission.wgsl similarity index 100% rename from crates/bevy_pbr/src/render/pbr_transmission.wgsl rename to crates/bevy_render_3d/src/render/pbr_transmission.wgsl diff --git a/crates/bevy_render_3d/src/render/pbr_types.wgsl b/crates/bevy_render_3d/src/render/pbr_types.wgsl new file mode 100644 index 0000000000000..29d479c4e315b --- /dev/null +++ b/crates/bevy_render_3d/src/render/pbr_types.wgsl @@ -0,0 +1,153 @@ +#define_import_path bevy_pbr::pbr_types + +// Since this is a hot path, try to keep the alignment and size of the struct members in mind. +// You can find the alignment and sizes at . +struct StandardMaterial { + base_color: vec4, + emissive: vec4, + attenuation_color: vec4, + uv_transform: mat3x3, + reflectance: vec3, + perceptual_roughness: f32, + metallic: f32, + diffuse_transmission: f32, + specular_transmission: f32, + thickness: f32, + ior: f32, + attenuation_distance: f32, + clearcoat: f32, + clearcoat_perceptual_roughness: f32, + anisotropy_strength: f32, + anisotropy_rotation: vec2, + // 'flags' is a bit field indicating various options. u32 is 32 bits so we have up to 32 options. + flags: u32, + alpha_cutoff: f32, + parallax_depth_scale: f32, + max_parallax_layer_count: f32, + lightmap_exposure: f32, + max_relief_mapping_search_steps: u32, + /// ID for specifying which deferred lighting pass should be used for rendering this material, if any. + deferred_lighting_pass_id: u32, +}; + +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +// NOTE: if these flags are updated or changed. Be sure to also update +// deferred_flags_from_mesh_material_flags and mesh_material_flags_from_deferred_flags +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +const STANDARD_MATERIAL_FLAGS_BASE_COLOR_TEXTURE_BIT: u32 = 1u; +const STANDARD_MATERIAL_FLAGS_EMISSIVE_TEXTURE_BIT: u32 = 2u; +const STANDARD_MATERIAL_FLAGS_METALLIC_ROUGHNESS_TEXTURE_BIT: u32 = 4u; +const STANDARD_MATERIAL_FLAGS_OCCLUSION_TEXTURE_BIT: u32 = 8u; +const STANDARD_MATERIAL_FLAGS_DOUBLE_SIDED_BIT: u32 = 16u; +const STANDARD_MATERIAL_FLAGS_UNLIT_BIT: u32 = 32u; +const STANDARD_MATERIAL_FLAGS_TWO_COMPONENT_NORMAL_MAP: u32 = 64u; +const STANDARD_MATERIAL_FLAGS_FLIP_NORMAL_MAP_Y: u32 = 128u; +const STANDARD_MATERIAL_FLAGS_FOG_ENABLED_BIT: u32 = 256u; +const STANDARD_MATERIAL_FLAGS_DEPTH_MAP_BIT: u32 = 512u; +const STANDARD_MATERIAL_FLAGS_SPECULAR_TRANSMISSION_TEXTURE_BIT: u32 = 1024u; +const STANDARD_MATERIAL_FLAGS_THICKNESS_TEXTURE_BIT: u32 = 2048u; +const STANDARD_MATERIAL_FLAGS_DIFFUSE_TRANSMISSION_TEXTURE_BIT: u32 = 4096u; +const STANDARD_MATERIAL_FLAGS_ATTENUATION_ENABLED_BIT: u32 = 8192u; +const STANDARD_MATERIAL_FLAGS_CLEARCOAT_TEXTURE_BIT: u32 = 16384u; +const STANDARD_MATERIAL_FLAGS_CLEARCOAT_ROUGHNESS_TEXTURE_BIT: u32 = 32768u; +const STANDARD_MATERIAL_FLAGS_CLEARCOAT_NORMAL_TEXTURE_BIT: u32 = 65536u; +const STANDARD_MATERIAL_FLAGS_ANISOTROPY_TEXTURE_BIT: u32 = 131072u; +const STANDARD_MATERIAL_FLAGS_SPECULAR_TEXTURE_BIT: u32 = 262144u; +const STANDARD_MATERIAL_FLAGS_SPECULAR_TINT_TEXTURE_BIT: u32 = 524288u; +const STANDARD_MATERIAL_FLAGS_ALPHA_MODE_RESERVED_BITS: u32 = 3758096384u; // (0b111u32 << 29) +const STANDARD_MATERIAL_FLAGS_ALPHA_MODE_OPAQUE: u32 = 0u; // (0u32 << 29) +const STANDARD_MATERIAL_FLAGS_ALPHA_MODE_MASK: u32 = 536870912u; // (1u32 << 29) +const STANDARD_MATERIAL_FLAGS_ALPHA_MODE_BLEND: u32 = 1073741824u; // (2u32 << 29) +const STANDARD_MATERIAL_FLAGS_ALPHA_MODE_PREMULTIPLIED: u32 = 1610612736u; // (3u32 << 29) +const STANDARD_MATERIAL_FLAGS_ALPHA_MODE_ADD: u32 = 2147483648u; // (4u32 << 29) +const STANDARD_MATERIAL_FLAGS_ALPHA_MODE_MULTIPLY: u32 = 2684354560u; // (5u32 << 29) +const STANDARD_MATERIAL_FLAGS_ALPHA_MODE_ALPHA_TO_COVERAGE: u32 = 3221225472u; // (6u32 << 29) +// ↑ To calculate/verify the values above, use the following playground: +// https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=7792f8dd6fc6a8d4d0b6b1776898a7f4 + + +// Creates a StandardMaterial with default values +fn standard_material_new() -> StandardMaterial { + var material: StandardMaterial; + + // NOTE: Keep in-sync with src/pbr_material.rs! + material.base_color = vec4(1.0, 1.0, 1.0, 1.0); + material.emissive = vec4(0.0, 0.0, 0.0, 1.0); + material.perceptual_roughness = 0.5; + material.metallic = 0.00; + material.reflectance = vec3(0.5); + material.diffuse_transmission = 0.0; + material.specular_transmission = 0.0; + material.thickness = 0.0; + material.ior = 1.5; + material.attenuation_distance = 1.0; + material.attenuation_color = vec4(1.0, 1.0, 1.0, 1.0); + material.clearcoat = 0.0; + material.clearcoat_perceptual_roughness = 0.0; + material.flags = STANDARD_MATERIAL_FLAGS_ALPHA_MODE_OPAQUE; + material.alpha_cutoff = 0.5; + material.parallax_depth_scale = 0.1; + material.max_parallax_layer_count = 16.0; + material.max_relief_mapping_search_steps = 5u; + material.deferred_lighting_pass_id = 1u; + // scale 1, translation 0, rotation 0 + material.uv_transform = mat3x3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0); + + return material; +} + +struct PbrInput { + material: StandardMaterial, + // Note: this gets monochromized upon deferred PbrInput reconstruction. + diffuse_occlusion: vec3, + // Note: this is 1.0 (entirely unoccluded) when SSAO and SSR are off. + specular_occlusion: f32, + frag_coord: vec4, + world_position: vec4, + // Normalized world normal used for shadow mapping as normal-mapping is not used for shadow + // mapping + world_normal: vec3, + // Normalized normal-mapped world normal used for lighting + N: vec3, + // Normalized view vector in world space, pointing from the fragment world position toward the + // view world position + V: vec3, + lightmap_light: vec3, + clearcoat_N: vec3, + anisotropy_strength: f32, + // These two aren't specific to anisotropy, but we only fill them in if + // we're doing anisotropy, so they're prefixed with `anisotropy_`. + anisotropy_T: vec3, + anisotropy_B: vec3, + is_orthographic: bool, + flags: u32, +}; + +// Creates a PbrInput with default values +fn pbr_input_new() -> PbrInput { + var pbr_input: PbrInput; + + pbr_input.material = standard_material_new(); + pbr_input.diffuse_occlusion = vec3(1.0); + // If SSAO is enabled, then this gets overwritten with proper specular occlusion. If its not, then we get specular environment map unoccluded (we have no data with which to occlude it with). + pbr_input.specular_occlusion = 1.0; + + pbr_input.frag_coord = vec4(0.0, 0.0, 0.0, 1.0); + pbr_input.world_position = vec4(0.0, 0.0, 0.0, 1.0); + pbr_input.world_normal = vec3(0.0, 0.0, 1.0); + + pbr_input.is_orthographic = false; + + pbr_input.N = vec3(0.0, 0.0, 1.0); + pbr_input.V = vec3(1.0, 0.0, 0.0); + + pbr_input.clearcoat_N = vec3(0.0); + pbr_input.anisotropy_T = vec3(0.0); + pbr_input.anisotropy_B = vec3(0.0); + + pbr_input.lightmap_light = vec3(0.0); + + pbr_input.flags = 0u; + + return pbr_input; +} diff --git a/crates/bevy_pbr/src/render/reset_indirect_batch_sets.wgsl b/crates/bevy_render_3d/src/render/reset_indirect_batch_sets.wgsl similarity index 100% rename from crates/bevy_pbr/src/render/reset_indirect_batch_sets.wgsl rename to crates/bevy_render_3d/src/render/reset_indirect_batch_sets.wgsl diff --git a/crates/bevy_render_3d/src/render/rgb9e5.wgsl b/crates/bevy_render_3d/src/render/rgb9e5.wgsl new file mode 100644 index 0000000000000..c635c83dfcc4c --- /dev/null +++ b/crates/bevy_render_3d/src/render/rgb9e5.wgsl @@ -0,0 +1,63 @@ +#define_import_path bevy_pbr::rgb9e5 + +const RGB9E5_EXPONENT_BITS = 5u; +const RGB9E5_MANTISSA_BITS = 9; +const RGB9E5_MANTISSA_BITSU = 9u; +const RGB9E5_EXP_BIAS = 15; +const RGB9E5_MAX_VALID_BIASED_EXP = 31u; + +//#define MAX_RGB9E5_EXP (RGB9E5_MAX_VALID_BIASED_EXP - RGB9E5_EXP_BIAS) +//#define RGB9E5_MANTISSA_VALUES (1< i32 { + let f = bitcast(x); + let biasedexponent = (f & 0x7F800000u) >> 23u; + return i32(biasedexponent) - 127; +} + +// https://www.khronos.org/registry/OpenGL/extensions/EXT/EXT_texture_shared_exponent.txt +fn vec3_to_rgb9e5_(rgb_in: vec3) -> u32 { + let rgb = clamp(rgb_in, vec3(0.0), vec3(MAX_RGB9E5_)); + + let maxrgb = max(rgb.r, max(rgb.g, rgb.b)); + var exp_shared = max(-RGB9E5_EXP_BIAS - 1, floor_log2_(maxrgb)) + 1 + RGB9E5_EXP_BIAS; + var denom = exp2(f32(exp_shared - RGB9E5_EXP_BIAS - RGB9E5_MANTISSA_BITS)); + + let maxm = i32(floor(maxrgb / denom + 0.5)); + if (maxm == RGB9E5_MANTISSA_VALUES) { + denom *= 2.0; + exp_shared += 1; + } + + let n = vec3(floor(rgb / denom + 0.5)); + + return (u32(exp_shared) << 27u) | (n.b << 18u) | (n.g << 9u) | (n.r << 0u); +} + +// Builtin extractBits() is not working on WEBGL or DX12 +// DX12: HLSL: Unimplemented("write_expr_math ExtractBits") +fn extract_bits(value: u32, offset: u32, bits: u32) -> u32 { + let mask = (1u << bits) - 1u; + return (value >> offset) & mask; +} + +fn rgb9e5_to_vec3_(v: u32) -> vec3 { + let exponent = i32(extract_bits(v, 27u, RGB9E5_EXPONENT_BITS)) - RGB9E5_EXP_BIAS - RGB9E5_MANTISSA_BITS; + let scale = exp2(f32(exponent)); + + return vec3( + f32(extract_bits(v, 0u, RGB9E5_MANTISSA_BITSU)), + f32(extract_bits(v, 9u, RGB9E5_MANTISSA_BITSU)), + f32(extract_bits(v, 18u, RGB9E5_MANTISSA_BITSU)) + ) * scale; +} diff --git a/crates/bevy_pbr/src/render/shadow_sampling.wgsl b/crates/bevy_render_3d/src/render/shadow_sampling.wgsl similarity index 100% rename from crates/bevy_pbr/src/render/shadow_sampling.wgsl rename to crates/bevy_render_3d/src/render/shadow_sampling.wgsl diff --git a/crates/bevy_pbr/src/render/shadows.wgsl b/crates/bevy_render_3d/src/render/shadows.wgsl similarity index 100% rename from crates/bevy_pbr/src/render/shadows.wgsl rename to crates/bevy_render_3d/src/render/shadows.wgsl diff --git a/crates/bevy_pbr/src/render/skin.rs b/crates/bevy_render_3d/src/render/skin.rs similarity index 100% rename from crates/bevy_pbr/src/render/skin.rs rename to crates/bevy_render_3d/src/render/skin.rs diff --git a/crates/bevy_pbr/src/render/skinning.wgsl b/crates/bevy_render_3d/src/render/skinning.wgsl similarity index 100% rename from crates/bevy_pbr/src/render/skinning.wgsl rename to crates/bevy_render_3d/src/render/skinning.wgsl diff --git a/crates/bevy_pbr/src/render/utils.wgsl b/crates/bevy_render_3d/src/render/utils.wgsl similarity index 100% rename from crates/bevy_pbr/src/render/utils.wgsl rename to crates/bevy_render_3d/src/render/utils.wgsl diff --git a/crates/bevy_pbr/src/render/view_transformations.wgsl b/crates/bevy_render_3d/src/render/view_transformations.wgsl similarity index 100% rename from crates/bevy_pbr/src/render/view_transformations.wgsl rename to crates/bevy_render_3d/src/render/view_transformations.wgsl diff --git a/crates/bevy_render_3d/src/render/wireframe.wgsl b/crates/bevy_render_3d/src/render/wireframe.wgsl new file mode 100644 index 0000000000000..981e5e1b1db3e --- /dev/null +++ b/crates/bevy_render_3d/src/render/wireframe.wgsl @@ -0,0 +1,12 @@ +#import bevy_pbr::forward_io::VertexOutput + +struct WireframeMaterial { + color: vec4, +}; + +@group(2) @binding(0) +var material: WireframeMaterial; +@fragment +fn fragment(in: VertexOutput) -> @location(0) vec4 { + return material.color; +} diff --git a/crates/bevy_pbr/src/ssao/mod.rs b/crates/bevy_render_3d/src/ssao/mod.rs similarity index 100% rename from crates/bevy_pbr/src/ssao/mod.rs rename to crates/bevy_render_3d/src/ssao/mod.rs diff --git a/crates/bevy_pbr/src/ssao/preprocess_depth.wgsl b/crates/bevy_render_3d/src/ssao/preprocess_depth.wgsl similarity index 100% rename from crates/bevy_pbr/src/ssao/preprocess_depth.wgsl rename to crates/bevy_render_3d/src/ssao/preprocess_depth.wgsl diff --git a/crates/bevy_pbr/src/ssao/spatial_denoise.wgsl b/crates/bevy_render_3d/src/ssao/spatial_denoise.wgsl similarity index 100% rename from crates/bevy_pbr/src/ssao/spatial_denoise.wgsl rename to crates/bevy_render_3d/src/ssao/spatial_denoise.wgsl diff --git a/crates/bevy_pbr/src/ssao/ssao.wgsl b/crates/bevy_render_3d/src/ssao/ssao.wgsl similarity index 100% rename from crates/bevy_pbr/src/ssao/ssao.wgsl rename to crates/bevy_render_3d/src/ssao/ssao.wgsl diff --git a/crates/bevy_pbr/src/ssao/ssao_utils.wgsl b/crates/bevy_render_3d/src/ssao/ssao_utils.wgsl similarity index 100% rename from crates/bevy_pbr/src/ssao/ssao_utils.wgsl rename to crates/bevy_render_3d/src/ssao/ssao_utils.wgsl diff --git a/crates/bevy_pbr/src/ssr/mod.rs b/crates/bevy_render_3d/src/ssr/mod.rs similarity index 100% rename from crates/bevy_pbr/src/ssr/mod.rs rename to crates/bevy_render_3d/src/ssr/mod.rs diff --git a/crates/bevy_pbr/src/ssr/raymarch.wgsl b/crates/bevy_render_3d/src/ssr/raymarch.wgsl similarity index 100% rename from crates/bevy_pbr/src/ssr/raymarch.wgsl rename to crates/bevy_render_3d/src/ssr/raymarch.wgsl diff --git a/crates/bevy_pbr/src/ssr/ssr.wgsl b/crates/bevy_render_3d/src/ssr/ssr.wgsl similarity index 100% rename from crates/bevy_pbr/src/ssr/ssr.wgsl rename to crates/bevy_render_3d/src/ssr/ssr.wgsl diff --git a/crates/bevy_pbr/src/volumetric_fog/mod.rs b/crates/bevy_render_3d/src/volumetric_fog/mod.rs similarity index 100% rename from crates/bevy_pbr/src/volumetric_fog/mod.rs rename to crates/bevy_render_3d/src/volumetric_fog/mod.rs diff --git a/crates/bevy_pbr/src/volumetric_fog/render.rs b/crates/bevy_render_3d/src/volumetric_fog/render.rs similarity index 100% rename from crates/bevy_pbr/src/volumetric_fog/render.rs rename to crates/bevy_render_3d/src/volumetric_fog/render.rs diff --git a/crates/bevy_pbr/src/volumetric_fog/volumetric_fog.wgsl b/crates/bevy_render_3d/src/volumetric_fog/volumetric_fog.wgsl similarity index 100% rename from crates/bevy_pbr/src/volumetric_fog/volumetric_fog.wgsl rename to crates/bevy_render_3d/src/volumetric_fog/volumetric_fog.wgsl diff --git a/examples/3d/anti_aliasing.rs b/examples/3d/anti_aliasing.rs index e29574588c71f..bcd1be9c3cff1 100644 --- a/examples/3d/anti_aliasing.rs +++ b/examples/3d/anti_aliasing.rs @@ -11,13 +11,13 @@ use bevy::{ }, core_pipeline::prepass::{DepthPrepass, MotionVectorPrepass}, image::{ImageSampler, ImageSamplerDescriptor}, - pbr::CascadeShadowConfigBuilder, prelude::*, render::{ camera::TemporalJitter, render_asset::RenderAssetUsages, render_resource::{Extent3d, TextureDimension, TextureFormat}, }, + render_3d::CascadeShadowConfigBuilder, }; fn main() { diff --git a/examples/3d/atmosphere.rs b/examples/3d/atmosphere.rs index 53c5c91dfa687..bd467d3b4ee2e 100644 --- a/examples/3d/atmosphere.rs +++ b/examples/3d/atmosphere.rs @@ -4,9 +4,9 @@ use std::f32::consts::PI; use bevy::{ core_pipeline::{bloom::Bloom, tonemapping::Tonemapping}, - pbr::{light_consts::lux, Atmosphere, AtmosphereSettings, CascadeShadowConfigBuilder}, prelude::*, render::camera::Exposure, + render_3d::{light_consts::lux, Atmosphere, AtmosphereSettings, CascadeShadowConfigBuilder}, }; fn main() { diff --git a/examples/3d/atmospheric_fog.rs b/examples/3d/atmospheric_fog.rs index e24736cdd1644..e359a78310a0c 100644 --- a/examples/3d/atmospheric_fog.rs +++ b/examples/3d/atmospheric_fog.rs @@ -8,8 +8,8 @@ //! | `S` | Toggle Directional Light Fog Influence | use bevy::{ - pbr::{CascadeShadowConfigBuilder, NotShadowCaster}, prelude::*, + render_3d::{CascadeShadowConfigBuilder, NotShadowCaster}, }; fn main() { diff --git a/examples/3d/clustered_decals.rs b/examples/3d/clustered_decals.rs index 108efe586ef1e..c04839ea3a720 100644 --- a/examples/3d/clustered_decals.rs +++ b/examples/3d/clustered_decals.rs @@ -7,15 +7,15 @@ use std::process; use bevy::{ color::palettes::css::{LIME, ORANGE_RED, SILVER}, input::mouse::AccumulatedMouseMotion, - pbr::{ - decal::{self, clustered::ClusteredDecal}, - ExtendedMaterial, MaterialExtension, - }, prelude::*, render::{ render_resource::{AsBindGroup, ShaderRef}, renderer::{RenderAdapter, RenderDevice}, }, + render_3d::{ + decal::{self, clustered::ClusteredDecal}, + ExtendedMaterial, MaterialExtension, + }, window::SystemCursorIcon, winit::cursor::CursorIcon, }; diff --git a/examples/3d/color_grading.rs b/examples/3d/color_grading.rs index 0b2616c1879b5..b088ab94700fa 100644 --- a/examples/3d/color_grading.rs +++ b/examples/3d/color_grading.rs @@ -7,9 +7,9 @@ use std::{ use bevy::{ ecs::system::EntityCommands, - pbr::CascadeShadowConfigBuilder, prelude::*, render::view::{ColorGrading, ColorGradingGlobal, ColorGradingSection}, + render_3d::CascadeShadowConfigBuilder, }; use std::fmt::Display; diff --git a/examples/3d/decal.rs b/examples/3d/decal.rs index 7fd45cd53cee6..f6a85af4d840d 100644 --- a/examples/3d/decal.rs +++ b/examples/3d/decal.rs @@ -5,8 +5,8 @@ mod camera_controller; use bevy::{ core_pipeline::prepass::DepthPrepass, - pbr::decal::{ForwardDecal, ForwardDecalMaterial, ForwardDecalMaterialExt}, prelude::*, + render_3d::decal::{ForwardDecal, ForwardDecalMaterial, ForwardDecalMaterialExt}, }; use camera_controller::{CameraController, CameraControllerPlugin}; use rand::{Rng, SeedableRng}; diff --git a/examples/3d/deferred_rendering.rs b/examples/3d/deferred_rendering.rs index d6e58fe5058a8..067de052b5943 100644 --- a/examples/3d/deferred_rendering.rs +++ b/examples/3d/deferred_rendering.rs @@ -7,11 +7,11 @@ use bevy::{ core_pipeline::prepass::{DeferredPrepass, DepthPrepass, MotionVectorPrepass, NormalPrepass}, image::ImageLoaderSettings, math::ops, - pbr::{ + prelude::*, + render_3d::{ CascadeShadowConfigBuilder, DefaultOpaqueRendererMethod, DirectionalLightShadowMap, NotShadowCaster, NotShadowReceiver, OpaqueRendererMethod, }, - prelude::*, }; fn main() { diff --git a/examples/3d/depth_of_field.rs b/examples/3d/depth_of_field.rs index d6ca77bbde0ca..d787d3ede4ee8 100644 --- a/examples/3d/depth_of_field.rs +++ b/examples/3d/depth_of_field.rs @@ -15,9 +15,9 @@ use bevy::{ dof::{self, DepthOfField, DepthOfFieldMode}, tonemapping::Tonemapping, }, - pbr::Lightmap, prelude::*, render::camera::PhysicalCameraParameters, + render_3d::Lightmap, }; /// The increments in which the user can adjust the focal distance, in meters diff --git a/examples/3d/edit_material_on_gltf.rs b/examples/3d/edit_material_on_gltf.rs index f9de5842a92fe..25c08f5936462 100644 --- a/examples/3d/edit_material_on_gltf.rs +++ b/examples/3d/edit_material_on_gltf.rs @@ -7,8 +7,9 @@ use bevy::{ color::{palettes, Color}, gltf::GltfAssetLabel, math::{Dir3, Vec3}, - pbr::{DirectionalLight, MeshMaterial3d, StandardMaterial}, + pbr::StandardMaterial, prelude::{Camera3d, Children, Commands, Component, Query, Res, ResMut, Transform, Trigger}, + render_3d::{DirectionalLight, MeshMaterial3d}, scene::{SceneInstanceReady, SceneRoot}, DefaultPlugins, }; diff --git a/examples/3d/fog.rs b/examples/3d/fog.rs index 9793ae0ad356a..7dd03ab888be1 100644 --- a/examples/3d/fog.rs +++ b/examples/3d/fog.rs @@ -16,8 +16,8 @@ use bevy::{ math::ops, - pbr::{NotShadowCaster, NotShadowReceiver}, prelude::*, + render_3d::{NotShadowCaster, NotShadowReceiver}, }; fn main() { diff --git a/examples/3d/fog_volumes.rs b/examples/3d/fog_volumes.rs index 68fc6d0ea783e..3c9fd58be53ca 100644 --- a/examples/3d/fog_volumes.rs +++ b/examples/3d/fog_volumes.rs @@ -7,8 +7,8 @@ use bevy::{ math::vec3, - pbr::{FogVolume, VolumetricFog, VolumetricLight}, prelude::*, + render_3d::{FogVolume, VolumetricFog, VolumetricLight}, }; /// Entry point. diff --git a/examples/3d/irradiance_volumes.rs b/examples/3d/irradiance_volumes.rs index 31529c421986d..9edc8071a5372 100644 --- a/examples/3d/irradiance_volumes.rs +++ b/examples/3d/irradiance_volumes.rs @@ -17,11 +17,11 @@ use bevy::{ color::palettes::css::*, core_pipeline::Skybox, math::{uvec3, vec3}, - pbr::{ - irradiance_volume::IrradianceVolume, ExtendedMaterial, MaterialExtension, NotShadowCaster, - }, prelude::*, render::render_resource::{AsBindGroup, ShaderRef, ShaderType}, + render_3d::{ + irradiance_volume::IrradianceVolume, ExtendedMaterial, MaterialExtension, NotShadowCaster, + }, window::PrimaryWindow, }; diff --git a/examples/3d/lighting.rs b/examples/3d/lighting.rs index b8d7883763019..04403447db34a 100644 --- a/examples/3d/lighting.rs +++ b/examples/3d/lighting.rs @@ -5,9 +5,9 @@ use std::f32::consts::PI; use bevy::{ color::palettes::css::*, - pbr::CascadeShadowConfigBuilder, prelude::*, render::camera::{Exposure, PhysicalCameraParameters}, + render_3d::CascadeShadowConfigBuilder, }; fn main() { diff --git a/examples/3d/lightmaps.rs b/examples/3d/lightmaps.rs index 975b37d7f2873..bfc3a4c972439 100644 --- a/examples/3d/lightmaps.rs +++ b/examples/3d/lightmaps.rs @@ -3,8 +3,8 @@ use argh::FromArgs; use bevy::{ core_pipeline::prepass::{DeferredPrepass, DepthPrepass, MotionVectorPrepass}, - pbr::{DefaultOpaqueRendererMethod, Lightmap}, prelude::*, + render_3d::{DefaultOpaqueRendererMethod, Lightmap}, }; /// Demonstrates lightmaps diff --git a/examples/3d/lines.rs b/examples/3d/lines.rs index d755aa434a2bb..341b800788223 100644 --- a/examples/3d/lines.rs +++ b/examples/3d/lines.rs @@ -1,7 +1,6 @@ //! Create a custom material to draw basic lines in 3D use bevy::{ - pbr::{MaterialPipeline, MaterialPipelineKey}, prelude::*, reflect::TypePath, render::{ @@ -12,6 +11,7 @@ use bevy::{ SpecializedMeshPipelineError, }, }, + render_3d::{MaterialPipeline, MaterialPipelineKey}, }; /// This example uses a shader source file from the assets subdirectory diff --git a/examples/3d/load_gltf.rs b/examples/3d/load_gltf.rs index ac82e24f09fc0..f9877f8dc7043 100644 --- a/examples/3d/load_gltf.rs +++ b/examples/3d/load_gltf.rs @@ -1,8 +1,8 @@ //! Loads and renders a glTF file as a scene. use bevy::{ - pbr::{CascadeShadowConfigBuilder, DirectionalLightShadowMap}, prelude::*, + render_3d::{CascadeShadowConfigBuilder, DirectionalLightShadowMap}, }; use std::f32::consts::*; diff --git a/examples/3d/meshlet.rs b/examples/3d/meshlet.rs index 0bab7d750198c..ca5310d94359b 100644 --- a/examples/3d/meshlet.rs +++ b/examples/3d/meshlet.rs @@ -6,12 +6,12 @@ mod camera_controller; use bevy::{ - pbr::{ + prelude::*, + render::render_resource::AsBindGroup, + render_3d::{ experimental::meshlet::{MeshletMesh3d, MeshletPlugin}, CascadeShadowConfigBuilder, DirectionalLightShadowMap, }, - prelude::*, - render::render_resource::AsBindGroup, }; use camera_controller::{CameraController, CameraControllerPlugin}; use std::{f32::consts::PI, path::Path, process::ExitCode}; diff --git a/examples/3d/mixed_lighting.rs b/examples/3d/mixed_lighting.rs index f7ebbd5cfca3a..99ee8f10a291e 100644 --- a/examples/3d/mixed_lighting.rs +++ b/examples/3d/mixed_lighting.rs @@ -1,9 +1,9 @@ //! Demonstrates how to combine baked and dynamic lighting. use bevy::{ - pbr::Lightmap, picking::{backend::HitData, pointer::PointerInteraction}, prelude::*, + render_3d::Lightmap, scene::SceneInstanceReady, }; diff --git a/examples/3d/pcss.rs b/examples/3d/pcss.rs index 922781829cc7b..fcdb8c9ebac46 100644 --- a/examples/3d/pcss.rs +++ b/examples/3d/pcss.rs @@ -9,12 +9,12 @@ use bevy::{ Skybox, }, math::vec3, - pbr::{CubemapVisibleEntities, ShadowFilteringMethod, VisibleMeshEntities}, prelude::*, render::{ camera::TemporalJitter, primitives::{CubemapFrusta, Frustum}, }, + render_3d::{CubemapVisibleEntities, ShadowFilteringMethod, VisibleMeshEntities}, }; use crate::widgets::{RadioButton, RadioButtonText, WidgetClickEvent, WidgetClickSender}; diff --git a/examples/3d/post_processing.rs b/examples/3d/post_processing.rs index 54a9e9089f163..d3f65c9609cb6 100644 --- a/examples/3d/post_processing.rs +++ b/examples/3d/post_processing.rs @@ -5,7 +5,8 @@ use std::f32::consts::PI; use bevy::{ - core_pipeline::post_process::ChromaticAberration, pbr::CascadeShadowConfigBuilder, prelude::*, + core_pipeline::post_process::ChromaticAberration, prelude::*, + render_3d::CascadeShadowConfigBuilder, }; /// The number of units per frame to add to or subtract from intensity when the diff --git a/examples/3d/scrolling_fog.rs b/examples/3d/scrolling_fog.rs index f65b4131701cd..33430831cf713 100644 --- a/examples/3d/scrolling_fog.rs +++ b/examples/3d/scrolling_fog.rs @@ -17,8 +17,8 @@ use bevy::{ ImageAddressMode, ImageFilterMode, ImageLoaderSettings, ImageSampler, ImageSamplerDescriptor, }, - pbr::{DirectionalLightShadowMap, FogVolume, VolumetricFog, VolumetricLight}, prelude::*, + render_3d::{DirectionalLightShadowMap, FogVolume, VolumetricFog, VolumetricLight}, }; /// Initializes the example. diff --git a/examples/3d/shadow_biases.rs b/examples/3d/shadow_biases.rs index afd469affff54..611f5dcca5b65 100644 --- a/examples/3d/shadow_biases.rs +++ b/examples/3d/shadow_biases.rs @@ -3,7 +3,7 @@ #[path = "../helpers/camera_controller.rs"] mod camera_controller; -use bevy::{pbr::ShadowFilteringMethod, prelude::*}; +use bevy::{prelude::*, render_3d::ShadowFilteringMethod}; use camera_controller::{CameraController, CameraControllerPlugin}; fn main() { diff --git a/examples/3d/shadow_caster_receiver.rs b/examples/3d/shadow_caster_receiver.rs index edc8631aa9abe..859b07f5a241a 100644 --- a/examples/3d/shadow_caster_receiver.rs +++ b/examples/3d/shadow_caster_receiver.rs @@ -4,8 +4,8 @@ use std::f32::consts::PI; use bevy::{ color::palettes::basic::{BLUE, LIME, RED}, - pbr::{CascadeShadowConfigBuilder, NotShadowCaster, NotShadowReceiver}, prelude::*, + render_3d::{CascadeShadowConfigBuilder, NotShadowCaster, NotShadowReceiver}, }; fn main() { diff --git a/examples/3d/split_screen.rs b/examples/3d/split_screen.rs index c11fb2e3ccd07..f6ff01ccc3ca2 100644 --- a/examples/3d/split_screen.rs +++ b/examples/3d/split_screen.rs @@ -3,7 +3,8 @@ use std::f32::consts::PI; use bevy::{ - pbr::CascadeShadowConfigBuilder, prelude::*, render::camera::Viewport, window::WindowResized, + prelude::*, render::camera::Viewport, render_3d::CascadeShadowConfigBuilder, + window::WindowResized, }; fn main() { diff --git a/examples/3d/spotlight.rs b/examples/3d/spotlight.rs index c92843404ef37..686e4dfef806a 100644 --- a/examples/3d/spotlight.rs +++ b/examples/3d/spotlight.rs @@ -5,8 +5,8 @@ use std::f32::consts::*; use bevy::{ color::palettes::basic::{MAROON, RED}, math::ops, - pbr::NotShadowCaster, prelude::*, + render_3d::NotShadowCaster, }; use rand::{Rng, SeedableRng}; use rand_chacha::ChaCha8Rng; diff --git a/examples/3d/ssao.rs b/examples/3d/ssao.rs index d036fb805dd03..55a3c113cea62 100644 --- a/examples/3d/ssao.rs +++ b/examples/3d/ssao.rs @@ -3,9 +3,9 @@ use bevy::{ anti_aliasing::experimental::taa::{TemporalAntiAliasPlugin, TemporalAntiAliasing}, math::ops, - pbr::{ScreenSpaceAmbientOcclusion, ScreenSpaceAmbientOcclusionQualityLevel}, prelude::*, render::camera::TemporalJitter, + render_3d::{ScreenSpaceAmbientOcclusion, ScreenSpaceAmbientOcclusionQualityLevel}, }; use std::f32::consts::PI; diff --git a/examples/3d/ssr.rs b/examples/3d/ssr.rs index a4d2c1b742c0f..4c3a64871ae35 100644 --- a/examples/3d/ssr.rs +++ b/examples/3d/ssr.rs @@ -12,11 +12,11 @@ use bevy::{ }, input::mouse::MouseWheel, math::{vec3, vec4}, - pbr::{ - DefaultOpaqueRendererMethod, ExtendedMaterial, MaterialExtension, ScreenSpaceReflections, - }, prelude::*, render::render_resource::{AsBindGroup, ShaderRef, ShaderType}, + render_3d::{ + DefaultOpaqueRendererMethod, ExtendedMaterial, MaterialExtension, ScreenSpaceReflections, + }, }; /// This example uses a shader source file from the assets subdirectory diff --git a/examples/3d/tonemapping.rs b/examples/3d/tonemapping.rs index e68e0d837c3f3..4f5d32525a759 100644 --- a/examples/3d/tonemapping.rs +++ b/examples/3d/tonemapping.rs @@ -2,7 +2,6 @@ use bevy::{ core_pipeline::tonemapping::Tonemapping, - pbr::CascadeShadowConfigBuilder, platform_support::collections::HashMap, prelude::*, reflect::TypePath, @@ -10,6 +9,7 @@ use bevy::{ render_resource::{AsBindGroup, ShaderRef}, view::{ColorGrading, ColorGradingGlobal, ColorGradingSection}, }, + render_3d::CascadeShadowConfigBuilder, }; use std::f32::consts::PI; diff --git a/examples/3d/transmission.rs b/examples/3d/transmission.rs index e4df69b3d96fa..38476076c4913 100644 --- a/examples/3d/transmission.rs +++ b/examples/3d/transmission.rs @@ -27,12 +27,12 @@ use bevy::{ tonemapping::Tonemapping, }, math::ops, - pbr::{NotShadowCaster, PointLightShadowMap, TransmittedShadowReceiver}, prelude::*, render::{ camera::{Exposure, TemporalJitter}, view::{ColorGrading, ColorGradingGlobal}, }, + render_3d::{NotShadowCaster, PointLightShadowMap, TransmittedShadowReceiver}, }; #[cfg(any(feature = "webgpu", not(target_arch = "wasm32")))] diff --git a/examples/3d/update_gltf_scene.rs b/examples/3d/update_gltf_scene.rs index 651fc038761fd..2ac9b16b7d63c 100644 --- a/examples/3d/update_gltf_scene.rs +++ b/examples/3d/update_gltf_scene.rs @@ -1,7 +1,7 @@ //! Update a scene from a glTF file, either by spawning the scene as a child of another entity, //! or by accessing the entities of the scene. -use bevy::{pbr::DirectionalLightShadowMap, prelude::*}; +use bevy::{prelude::*, render_3d::DirectionalLightShadowMap}; fn main() { App::new() diff --git a/examples/3d/visibility_range.rs b/examples/3d/visibility_range.rs index 50c82f69f5583..dec0460227c0f 100644 --- a/examples/3d/visibility_range.rs +++ b/examples/3d/visibility_range.rs @@ -6,9 +6,9 @@ use bevy::{ core_pipeline::prepass::{DepthPrepass, NormalPrepass}, input::mouse::MouseWheel, math::vec3, - pbr::{light_consts::lux::FULL_DAYLIGHT, CascadeShadowConfigBuilder}, prelude::*, render::view::VisibilityRange, + render_3d::{light_consts::lux::FULL_DAYLIGHT, CascadeShadowConfigBuilder}, }; // Where the camera is focused. diff --git a/examples/3d/volumetric_fog.rs b/examples/3d/volumetric_fog.rs index 9cfef624c6594..8c09c733dd24d 100644 --- a/examples/3d/volumetric_fog.rs +++ b/examples/3d/volumetric_fog.rs @@ -4,8 +4,8 @@ use bevy::{ color::palettes::css::RED, core_pipeline::{bloom::Bloom, tonemapping::Tonemapping, Skybox}, math::vec3, - pbr::{FogVolume, VolumetricFog, VolumetricLight}, prelude::*, + render_3d::{FogVolume, VolumetricFog, VolumetricLight}, }; const DIRECTIONAL_LIGHT_MOVEMENT_SPEED: f32 = 0.02; diff --git a/examples/animation/animated_mesh.rs b/examples/animation/animated_mesh.rs index ecea86fb178a7..bdf0ae6738d76 100644 --- a/examples/animation/animated_mesh.rs +++ b/examples/animation/animated_mesh.rs @@ -2,7 +2,7 @@ use std::f32::consts::PI; -use bevy::{pbr::CascadeShadowConfigBuilder, prelude::*, scene::SceneInstanceReady}; +use bevy::{prelude::*, render_3d::CascadeShadowConfigBuilder, scene::SceneInstanceReady}; // An example asset that contains a mesh and animation. const GLTF_PATH: &str = "models/animated/Fox.glb"; diff --git a/examples/animation/animated_mesh_control.rs b/examples/animation/animated_mesh_control.rs index 0dafd0de11892..8b588a268260d 100644 --- a/examples/animation/animated_mesh_control.rs +++ b/examples/animation/animated_mesh_control.rs @@ -2,7 +2,7 @@ use std::{f32::consts::PI, time::Duration}; -use bevy::{animation::RepeatAnimation, pbr::CascadeShadowConfigBuilder, prelude::*}; +use bevy::{animation::RepeatAnimation, prelude::*, render_3d::CascadeShadowConfigBuilder}; const FOX_PATH: &str = "models/animated/Fox.glb"; diff --git a/examples/animation/animated_mesh_events.rs b/examples/animation/animated_mesh_events.rs index 2048f573fd704..6e56dd0fd54d1 100644 --- a/examples/animation/animated_mesh_events.rs +++ b/examples/animation/animated_mesh_events.rs @@ -3,8 +3,8 @@ use std::{f32::consts::PI, time::Duration}; use bevy::{ - animation::AnimationTargetId, color::palettes::css::WHITE, pbr::CascadeShadowConfigBuilder, - prelude::*, + animation::AnimationTargetId, color::palettes::css::WHITE, prelude::*, + render_3d::CascadeShadowConfigBuilder, }; use rand::{Rng, SeedableRng}; use rand_chacha::ChaCha8Rng; diff --git a/examples/camera/first_person_view_model.rs b/examples/camera/first_person_view_model.rs index 09ff0d17bf1a6..8cc4111e31d34 100644 --- a/examples/camera/first_person_view_model.rs +++ b/examples/camera/first_person_view_model.rs @@ -45,8 +45,8 @@ use std::f32::consts::FRAC_PI_2; use bevy::{ - color::palettes::tailwind, input::mouse::AccumulatedMouseMotion, pbr::NotShadowCaster, - prelude::*, render::view::RenderLayers, + color::palettes::tailwind, input::mouse::AccumulatedMouseMotion, prelude::*, + render::view::RenderLayers, render_3d::NotShadowCaster, }; fn main() { diff --git a/examples/shader/custom_render_phase.rs b/examples/shader/custom_render_phase.rs index 47aad1b88faef..53cf7d149ed5f 100644 --- a/examples/shader/custom_render_phase.rs +++ b/examples/shader/custom_render_phase.rs @@ -19,10 +19,6 @@ use bevy::{ system::{lifetimeless::SRes, SystemParamItem}, }, math::FloatOrd, - pbr::{ - DrawMesh, MeshInputUniform, MeshPipeline, MeshPipelineKey, MeshPipelineViewLayoutKey, - MeshUniform, RenderMeshInstances, SetMeshBindGroup, SetMeshViewBindGroup, - }, platform_support::collections::HashSet, prelude::*, render::{ @@ -56,6 +52,10 @@ use bevy::{ view::{ExtractedView, RenderVisibleEntities, RetainedViewEntity, ViewTarget}, Extract, Render, RenderApp, RenderDebugFlags, RenderSet, }, + render_3d::{ + DrawMesh, MeshInputUniform, MeshPipeline, MeshPipelineKey, MeshPipelineViewLayoutKey, + MeshUniform, RenderMeshInstances, SetMeshBindGroup, SetMeshViewBindGroup, + }, }; use nonmax::NonMaxU32; diff --git a/examples/shader/custom_shader_instancing.rs b/examples/shader/custom_shader_instancing.rs index cd5909c36fff1..3fc5c898214cb 100644 --- a/examples/shader/custom_shader_instancing.rs +++ b/examples/shader/custom_shader_instancing.rs @@ -13,9 +13,6 @@ use bevy::{ query::QueryItem, system::{lifetimeless::*, SystemParamItem}, }, - pbr::{ - MeshPipeline, MeshPipelineKey, RenderMeshInstances, SetMeshBindGroup, SetMeshViewBindGroup, - }, prelude::*, render::{ extract_component::{ExtractComponent, ExtractComponentPlugin}, @@ -33,6 +30,9 @@ use bevy::{ view::{ExtractedView, NoFrustumCulling, NoIndirectDrawing}, Render, RenderApp, RenderSet, }, + render_3d::{ + MeshPipeline, MeshPipelineKey, RenderMeshInstances, SetMeshBindGroup, SetMeshViewBindGroup, + }, }; use bytemuck::{Pod, Zeroable}; diff --git a/examples/shader/custom_vertex_attribute.rs b/examples/shader/custom_vertex_attribute.rs index 4cc8ea7dc5fe4..2bb88eaca7cee 100644 --- a/examples/shader/custom_vertex_attribute.rs +++ b/examples/shader/custom_vertex_attribute.rs @@ -1,7 +1,6 @@ //! A shader that reads a mesh's custom vertex attribute. use bevy::{ - pbr::{MaterialPipeline, MaterialPipelineKey}, prelude::*, reflect::TypePath, render::{ @@ -11,6 +10,7 @@ use bevy::{ VertexFormat, }, }, + render_3d::{MaterialPipeline, MaterialPipelineKey}, }; /// This example uses a shader source file from the assets subdirectory diff --git a/examples/shader/extended_material.rs b/examples/shader/extended_material.rs index 3c5102db8ae58..23370d0f98225 100644 --- a/examples/shader/extended_material.rs +++ b/examples/shader/extended_material.rs @@ -2,9 +2,9 @@ use bevy::{ color::palettes::basic::RED, - pbr::{ExtendedMaterial, MaterialExtension, OpaqueRendererMethod}, prelude::*, render::render_resource::*, + render_3d::{ExtendedMaterial, MaterialExtension, OpaqueRendererMethod}, }; /// This example uses a shader source file from the assets subdirectory diff --git a/examples/shader/shader_defs.rs b/examples/shader/shader_defs.rs index 950ec182b4609..02f1a18848f7f 100644 --- a/examples/shader/shader_defs.rs +++ b/examples/shader/shader_defs.rs @@ -1,7 +1,6 @@ //! A shader that uses "shaders defs", which selectively toggle parts of a shader. use bevy::{ - pbr::{MaterialPipeline, MaterialPipelineKey}, prelude::*, reflect::TypePath, render::{ @@ -10,6 +9,7 @@ use bevy::{ AsBindGroup, RenderPipelineDescriptor, ShaderRef, SpecializedMeshPipelineError, }, }, + render_3d::{MaterialPipeline, MaterialPipelineKey}, }; /// This example uses a shader source file from the assets subdirectory diff --git a/examples/shader/shader_material_glsl.rs b/examples/shader/shader_material_glsl.rs index 1f25302a727b9..1d7a8ed20fdc5 100644 --- a/examples/shader/shader_material_glsl.rs +++ b/examples/shader/shader_material_glsl.rs @@ -1,7 +1,6 @@ //! A shader that uses the GLSL shading language. use bevy::{ - pbr::{MaterialPipeline, MaterialPipelineKey}, prelude::*, reflect::TypePath, render::{ @@ -10,6 +9,7 @@ use bevy::{ AsBindGroup, RenderPipelineDescriptor, ShaderRef, SpecializedMeshPipelineError, }, }, + render_3d::{MaterialPipeline, MaterialPipelineKey}, }; /// This example uses shader source files from the assets subdirectory diff --git a/examples/shader/shader_material_wesl.rs b/examples/shader/shader_material_wesl.rs index 108093de78664..c7dc5db2fb466 100644 --- a/examples/shader/shader_material_wesl.rs +++ b/examples/shader/shader_material_wesl.rs @@ -1,7 +1,6 @@ //! A shader that uses the WESL shading language. use bevy::{ - pbr::{MaterialPipeline, MaterialPipelineKey}, prelude::*, reflect::TypePath, render::{ @@ -11,6 +10,7 @@ use bevy::{ SpecializedMeshPipelineError, }, }, + render_3d::{MaterialPipeline, MaterialPipelineKey}, }; /// This example uses shader source files from the assets subdirectory diff --git a/examples/shader/shader_prepass.rs b/examples/shader/shader_prepass.rs index 00059a35e084b..6499a2f6a065f 100644 --- a/examples/shader/shader_prepass.rs +++ b/examples/shader/shader_prepass.rs @@ -4,10 +4,11 @@ use bevy::{ core_pipeline::prepass::{DepthPrepass, MotionVectorPrepass, NormalPrepass}, - pbr::{NotShadowCaster, PbrPlugin}, + pbr::PbrPlugin, prelude::*, reflect::TypePath, render::render_resource::{AsBindGroup, ShaderRef, ShaderType}, + render_3d::NotShadowCaster, }; /// This example uses a shader source file from the assets subdirectory diff --git a/examples/shader/specialized_mesh_pipeline.rs b/examples/shader/specialized_mesh_pipeline.rs index 66f42f5872ecc..9b37e7d171de9 100644 --- a/examples/shader/specialized_mesh_pipeline.rs +++ b/examples/shader/specialized_mesh_pipeline.rs @@ -10,10 +10,6 @@ use bevy::{ core_pipeline::core_3d::{Opaque3d, Opaque3dBatchSetKey, Opaque3dBinKey, CORE_3D_DEPTH_FORMAT}, ecs::{component::Tick, system::StaticSystemParam}, math::{vec3, vec4}, - pbr::{ - DrawMesh, MeshPipeline, MeshPipelineKey, MeshPipelineViewLayoutKey, RenderMeshInstances, - SetMeshBindGroup, SetMeshViewBindGroup, - }, prelude::*, render::{ batching::{ @@ -41,6 +37,10 @@ use bevy::{ view::{self, ExtractedView, RenderVisibleEntities, ViewTarget, VisibilityClass}, Render, RenderApp, RenderSet, }, + render_3d::{ + DrawMesh, MeshPipeline, MeshPipelineKey, MeshPipelineViewLayoutKey, RenderMeshInstances, + SetMeshBindGroup, SetMeshViewBindGroup, + }, }; const SHADER_ASSET_PATH: &str = "shaders/specialized_mesh_pipeline.wgsl"; diff --git a/examples/stress_tests/many_cubes.rs b/examples/stress_tests/many_cubes.rs index 1d8a50313152f..dcf6e89807a41 100644 --- a/examples/stress_tests/many_cubes.rs +++ b/examples/stress_tests/many_cubes.rs @@ -14,7 +14,6 @@ use argh::FromArgs; use bevy::{ diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin}, math::{DVec2, DVec3}, - pbr::NotShadowCaster, prelude::*, render::{ batching::NoAutomaticBatching, @@ -22,6 +21,7 @@ use bevy::{ render_resource::{Extent3d, TextureDimension, TextureFormat}, view::{NoCpuCulling, NoFrustumCulling, NoIndirectDrawing}, }, + render_3d::NotShadowCaster, window::{PresentMode, WindowResolution}, winit::{UpdateMode, WinitSettings}, }; diff --git a/examples/stress_tests/many_foxes.rs b/examples/stress_tests/many_foxes.rs index c1284c9bd6c1f..25762d468055a 100644 --- a/examples/stress_tests/many_foxes.rs +++ b/examples/stress_tests/many_foxes.rs @@ -6,8 +6,8 @@ use std::{f32::consts::PI, time::Duration}; use argh::FromArgs; use bevy::{ diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin}, - pbr::CascadeShadowConfigBuilder, prelude::*, + render_3d::CascadeShadowConfigBuilder, window::{PresentMode, WindowResolution}, winit::{UpdateMode, WinitSettings}, }; diff --git a/examples/stress_tests/many_lights.rs b/examples/stress_tests/many_lights.rs index a19f02d156725..8535d64a1c3e7 100644 --- a/examples/stress_tests/many_lights.rs +++ b/examples/stress_tests/many_lights.rs @@ -7,9 +7,9 @@ use bevy::{ color::palettes::css::DEEP_PINK, diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin}, math::{DVec2, DVec3}, - pbr::{ExtractedPointLight, GlobalClusterableObjectMeta}, prelude::*, render::{camera::ScalingMode, Render, RenderApp, RenderSet}, + render_3d::{ExtractedPointLight, GlobalClusterableObjectMeta}, window::{PresentMode, WindowResolution}, winit::{UpdateMode, WinitSettings}, }; diff --git a/examples/tools/scene_viewer/main.rs b/examples/tools/scene_viewer/main.rs index 0266a22ee0a06..a3170bcd2c7b1 100644 --- a/examples/tools/scene_viewer/main.rs +++ b/examples/tools/scene_viewer/main.rs @@ -11,12 +11,12 @@ use argh::FromArgs; use bevy::{ core_pipeline::prepass::{DeferredPrepass, DepthPrepass}, - pbr::DefaultOpaqueRendererMethod, prelude::*, render::{ experimental::occlusion_culling::OcclusionCulling, primitives::{Aabb, Sphere}, }, + render_3d::DefaultOpaqueRendererMethod, }; #[path = "../../helpers/camera_controller.rs"] From 14476159dff1b2bdf9228aad2b3e9895b77e2255 Mon Sep 17 00:00:00 2001 From: Lucas Farias Date: Sun, 30 Mar 2025 23:11:01 -0300 Subject: [PATCH 2/4] Add `bevy_render_3d` crate feature to docs --- docs/cargo_features.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/cargo_features.md b/docs/cargo_features.md index f15fa1c4c6683..da46243526fbe 100644 --- a/docs/cargo_features.md +++ b/docs/cargo_features.md @@ -30,6 +30,7 @@ The default feature set enables most of the expected features of a game engine, |bevy_pbr|Adds PBR rendering| |bevy_picking|Provides picking functionality| |bevy_render|Provides rendering functionality| +|bevy_render_3d|Provides functionality for rendering in 3d| |bevy_scene|Provides scene functionality| |bevy_sprite|Provides sprite functionality| |bevy_sprite_picking_backend|Provides an implementation for picking sprites| From 6dcf4e0a8a5304b870e7a019b5927bd62590ccf3 Mon Sep 17 00:00:00 2001 From: Lucas Farias Date: Thu, 3 Apr 2025 10:53:18 -0300 Subject: [PATCH 3/4] Add `is_invalid` for `UntypedAssetId` --- crates/bevy_asset/src/id.rs | 21 ++++++++++++++++- .../src/meshlet/instance_manager.rs | 23 +++++++++---------- crates/bevy_render_3d/src/render/mesh.rs | 23 +++++++++---------- 3 files changed, 42 insertions(+), 25 deletions(-) diff --git a/crates/bevy_asset/src/id.rs b/crates/bevy_asset/src/id.rs index 0f146eda65582..54a4efa414062 100644 --- a/crates/bevy_asset/src/id.rs +++ b/crates/bevy_asset/src/id.rs @@ -1,5 +1,5 @@ use crate::{Asset, AssetIndex}; -use bevy_reflect::{std_traits::ReflectDefault, Reflect}; +use bevy_reflect::{std_traits::ReflectDefault, Reflect, TypePath}; use serde::{Deserialize, Serialize}; use uuid::Uuid; @@ -261,6 +261,25 @@ impl UntypedAssetId { UntypedAssetId::Uuid { uuid, .. } => InternalAssetId::Uuid(uuid), } } + + /// Checks if [`UntypedAssetId`] has an invalid [`Uuid`]. + /// This is weaker than comparing equality with the untyped asset id returned + /// by `AssetId::invalid().untyped()` because the [`TypeId`] is ignored. + pub fn is_invalid(&self) -> bool { + #[derive(Asset, TypePath)] + struct DummyAsset; + + match self { + Self::Index { + type_id: _, + index: _, + } => false, + Self::Uuid { + type_id: _, + uuid: asset_uuid, + } => asset_uuid == &AssetId::::INVALID_UUID, + } + } } impl Display for UntypedAssetId { diff --git a/crates/bevy_render_3d/src/meshlet/instance_manager.rs b/crates/bevy_render_3d/src/meshlet/instance_manager.rs index 40a2d93277a15..711da9c08d2f6 100644 --- a/crates/bevy_render_3d/src/meshlet/instance_manager.rs +++ b/crates/bevy_render_3d/src/meshlet/instance_manager.rs @@ -2,9 +2,9 @@ use super::{meshlet_mesh_manager::MeshletMeshManager, MeshletMesh, MeshletMesh3d use crate::{ Material, MaterialBindingId, MeshFlags, MeshTransforms, MeshUniform, NotShadowCaster, NotShadowReceiver, PreviousGlobalTransform, RenderMaterialBindings, RenderMaterialInstances, - RenderMeshMaterialIds, StandardMaterial, + RenderMeshMaterialIds, }; -use bevy_asset::{AssetEvent, AssetId, AssetServer, Assets, UntypedAssetId}; +use bevy_asset::{AssetEvent, AssetServer, Assets, UntypedAssetId}; use bevy_ecs::{ entity::{Entities, Entity, EntityHashMap}, event::EventReader, @@ -113,16 +113,15 @@ impl InstanceManager { }; let mesh_material = mesh_material_ids.mesh_material(instance); - let mesh_material_binding_id = - if mesh_material != AssetId::::invalid().untyped() { - render_material_bindings - .get(&mesh_material) - .cloned() - .unwrap_or_default() - } else { - // Use a dummy binding ID if the mesh has no material - MaterialBindingId::default() - }; + let mesh_material_binding_id = if !mesh_material.is_invalid() { + render_material_bindings + .get(&mesh_material) + .cloned() + .unwrap_or_default() + } else { + // Use a dummy binding ID if the mesh has no material + MaterialBindingId::default() + }; let mesh_uniform = MeshUniform::new( &transforms, diff --git a/crates/bevy_render_3d/src/render/mesh.rs b/crates/bevy_render_3d/src/render/mesh.rs index 15bfb895cd21c..424debede9b5f 100644 --- a/crates/bevy_render_3d/src/render/mesh.rs +++ b/crates/bevy_render_3d/src/render/mesh.rs @@ -1172,19 +1172,18 @@ impl RenderMeshInstanceGpuBuilder { // yet loaded. In that case, add the mesh to // `meshes_to_reextract_next_frame` and bail. let mesh_material = mesh_material_ids.mesh_material(entity); - let mesh_material_binding_id = - if mesh_material != AssetId::::invalid().untyped() { - match render_material_bindings.get(&mesh_material) { - Some(binding_id) => *binding_id, - None => { - meshes_to_reextract_next_frame.insert(entity); - return None; - } + let mesh_material_binding_id = if !mesh_material.is_invalid() { + match render_material_bindings.get(&mesh_material) { + Some(binding_id) => *binding_id, + None => { + meshes_to_reextract_next_frame.insert(entity); + return None; } - } else { - // Use a dummy material binding ID. - MaterialBindingId::default() - }; + } + } else { + // Use a dummy material binding ID. + MaterialBindingId::default() + }; self.shared.material_bindings_index = mesh_material_binding_id; let lightmap_slot = match render_lightmaps.render_lightmaps.get(&entity) { From bf0f5faa4abfdd70f3cc5fc8ecf149abf6580ae9 Mon Sep 17 00:00:00 2001 From: Lucas Farias Date: Thu, 3 Apr 2025 12:46:01 -0300 Subject: [PATCH 4/4] Clean up `Cargo.toml` of `bevy_pbr` and `bevy_render_3d` --- Cargo.toml | 4 +- crates/bevy_internal/Cargo.toml | 23 +++++---- crates/bevy_pbr/Cargo.toml | 48 +------------------ crates/bevy_pbr/src/lib.rs | 5 +- crates/bevy_pbr/src/pbr_material.rs | 18 +++++-- crates/bevy_render_3d/Cargo.toml | 25 +++++----- .../src/light/directional_light.rs | 4 +- .../bevy_render_3d/src/light/point_light.rs | 4 +- crates/bevy_render_3d/src/light/spot_light.rs | 4 +- crates/bevy_render_3d/src/render/light.rs | 20 ++++---- crates/bevy_render_3d/src/render/mesh.rs | 15 +----- .../src/render/mesh_view_bindings.rs | 8 ++-- docs/cargo_features.md | 2 +- 13 files changed, 69 insertions(+), 111 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 540008bcc252a..ab6fa4a55a5e1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -479,7 +479,7 @@ pbr_multi_layer_material_textures = [ pbr_anisotropy_texture = ["bevy_internal/pbr_anisotropy_texture"] # Enable support for PCSS, at the risk of blowing past the global, per-shader sampler limit on older/lower-end GPUs -experimental_pbr_pcss = ["bevy_internal/experimental_pbr_pcss"] +experimental_pcss = ["bevy_internal/experimental_pcss"] # Enable support for specular textures in the `StandardMaterial`, at the risk of blowing past the global, per-shader texture limit on older/lower-end GPUs pbr_specular_textures = ["bevy_internal/pbr_specular_textures"] @@ -4115,7 +4115,7 @@ wasm = true name = "pcss" path = "examples/3d/pcss.rs" doc-scrape-examples = true -required-features = ["experimental_pbr_pcss"] +required-features = ["experimental_pcss"] [package.metadata.example.pcss] name = "Percentage-closer soft shadows" diff --git a/crates/bevy_internal/Cargo.toml b/crates/bevy_internal/Cargo.toml index 37eece8ab6fde..609aff9a050f1 100644 --- a/crates/bevy_internal/Cargo.toml +++ b/crates/bevy_internal/Cargo.toml @@ -17,8 +17,8 @@ trace = [ "bevy_anti_aliasing?/trace", "bevy_ecs/trace", "bevy_log/trace", - "bevy_pbr?/trace", "bevy_render?/trace", + "bevy_render_3d?/trace", "bevy_winit?/trace", ] trace_chrome = ["bevy_log/tracing-chrome"] @@ -81,7 +81,7 @@ symphonia-wav = ["bevy_audio/symphonia-wav"] # Shader formats shader_format_glsl = [ "bevy_render/shader_format_glsl", - "bevy_pbr?/shader_format_glsl", + "bevy_render_3d?/shader_format_glsl", ] shader_format_spirv = ["bevy_render/shader_format_spirv"] shader_format_wesl = ["bevy_render/shader_format_wesl"] @@ -137,7 +137,7 @@ pbr_anisotropy_texture = [ ] # Percentage-closer soft shadows -experimental_pbr_pcss = ["bevy_pbr?/experimental_pbr_pcss"] +experimental_pcss = ["bevy_render_3d?/experimental_pcss"] # Specular textures in `StandardMaterial`: pbr_specular_textures = [ @@ -149,8 +149,8 @@ pbr_specular_textures = [ webgl = [ "bevy_core_pipeline?/webgl", "bevy_anti_aliasing?/webgl", - "bevy_pbr?/webgl", "bevy_render?/webgl", + "bevy_render_3d?/webgl", "bevy_gizmos?/webgl", "bevy_sprite?/webgl", ] @@ -158,8 +158,8 @@ webgl = [ webgpu = [ "bevy_core_pipeline?/webgpu", "bevy_anti_aliasing?/webgpu", - "bevy_pbr?/webgpu", "bevy_render?/webgpu", + "bevy_render_3d?/webgpu", "bevy_gizmos?/webgpu", "bevy_sprite?/webgpu", ] @@ -200,7 +200,11 @@ bevy_render = [ "bevy_color/wgpu-types", "bevy_color/encase", ] -bevy_render_3d = ["dep:bevy_render_3d", "bevy_gizmos?/bevy_render_3d"] +bevy_render_3d = [ + "bevy_render", + "dep:bevy_render_3d", + "bevy_gizmos?/bevy_render_3d", +] # Enable assertions to check the validity of parameters passed to glam glam_assert = ["bevy_math/glam_assert"] @@ -226,10 +230,10 @@ bevy_debug_stepping = [ ] # Enables the meshlet renderer for dense high-poly scenes (experimental) -meshlet = ["bevy_pbr?/meshlet"] +meshlet = ["bevy_render_3d?/meshlet", "bevy_pbr?/meshlet"] -# Enables processing meshes into meshlet meshes for bevy_pbr -meshlet_processor = ["bevy_pbr?/meshlet_processor"] +# Enables processing meshes into meshlet meshes for bevy_render_3d +meshlet_processor = ["bevy_render_3d?/meshlet"] # Provides a collection of developer tools bevy_dev_tools = ["dep:bevy_dev_tools"] @@ -297,6 +301,7 @@ std = [ "bevy_math/std", "bevy_platform_support/std", "bevy_reflect/std", + "bevy_render_3d?/std", "bevy_state?/std", "bevy_time/std", "bevy_transform/std", diff --git a/crates/bevy_pbr/Cargo.toml b/crates/bevy_pbr/Cargo.toml index ada9f68d9e45c..a6b1689ded709 100644 --- a/crates/bevy_pbr/Cargo.toml +++ b/crates/bevy_pbr/Cargo.toml @@ -9,71 +9,27 @@ license = "MIT OR Apache-2.0" keywords = ["bevy"] [features] -webgl = [] -webgpu = [] pbr_transmission_textures = [] pbr_multi_layer_material_textures = [] pbr_anisotropy_texture = [] -experimental_pbr_pcss = [] pbr_specular_textures = [] -shader_format_glsl = ["bevy_render/shader_format_glsl"] -trace = ["bevy_render/trace"] -# Enables the meshlet renderer for dense high-poly scenes (experimental) -meshlet = ["dep:lz4_flex", "dep:range-alloc", "dep:half", "dep:bevy_tasks"] -# Enables processing meshes into meshlet meshes -meshlet_processor = [ - "meshlet", - "dep:meshopt", - "dep:metis", - "dep:itertools", - "dep:bitvec", -] +# Enables `StandardMaterial` for meshlets (experimental) +meshlet = [] [dependencies] # bevy bevy_app = { path = "../bevy_app", version = "0.16.0-dev" } bevy_asset = { path = "../bevy_asset", version = "0.16.0-dev" } bevy_color = { path = "../bevy_color", version = "0.16.0-dev" } -bevy_core_pipeline = { path = "../bevy_core_pipeline", version = "0.16.0-dev" } -bevy_derive = { path = "../bevy_derive", version = "0.16.0-dev" } -bevy_diagnostic = { path = "../bevy_diagnostic", version = "0.16.0-dev" } bevy_ecs = { path = "../bevy_ecs", version = "0.16.0-dev" } bevy_image = { path = "../bevy_image", version = "0.16.0-dev" } bevy_math = { path = "../bevy_math", version = "0.16.0-dev" } bevy_reflect = { path = "../bevy_reflect", version = "0.16.0-dev" } bevy_render = { path = "../bevy_render", version = "0.16.0-dev" } bevy_render_3d = { path = "../bevy_render_3d", version = "0.16.0-dev" } -bevy_tasks = { path = "../bevy_tasks", version = "0.16.0-dev", optional = true } -bevy_transform = { path = "../bevy_transform", version = "0.16.0-dev" } -bevy_utils = { path = "../bevy_utils", version = "0.16.0-dev" } -bevy_window = { path = "../bevy_window", version = "0.16.0-dev" } -bevy_platform_support = { path = "../bevy_platform_support", version = "0.16.0-dev", default-features = false, features = [ - "std", -] } # other bitflags = "2.3" -fixedbitset = "0.5" -thiserror = { version = "2", default-features = false } -derive_more = { version = "1", default-features = false, features = ["from"] } -# meshlet -lz4_flex = { version = "0.11", default-features = false, features = [ - "frame", -], optional = true } -range-alloc = { version = "0.1.3", optional = true } -half = { version = "2", features = ["bytemuck"], optional = true } -meshopt = { version = "0.4.1", optional = true } -metis = { version = "0.2", optional = true } -itertools = { version = "0.14", optional = true } -bitvec = { version = "1", optional = true } -# direct dependency required for derive macro -bytemuck = { version = "1", features = ["derive", "must_cast"] } -radsort = "0.1" -smallvec = "1.6" -nonmax = "0.5" -static_assertions = "1" -tracing = { version = "0.1", default-features = false, features = ["std"] } -offset-allocator = "0.2" [lints] workspace = true diff --git a/crates/bevy_pbr/src/lib.rs b/crates/bevy_pbr/src/lib.rs index 977eb94e699b9..3764d997845c4 100644 --- a/crates/bevy_pbr/src/lib.rs +++ b/crates/bevy_pbr/src/lib.rs @@ -49,8 +49,9 @@ const RGB9E5_FUNCTIONS_HANDLE: Handle = /// Sets up the entire PBR infrastructure of bevy. pub struct PbrPlugin { - /// Controls if the prepass is enabled for the [`StandardMaterial`]. - /// For more information about what a prepass is, see the [`bevy_core_pipeline::prepass`] docs. + /// Controls if the prepass is enabled for the [`StandardMaterial`]. + /// Prepasses are run before the main pass and are used to generate things like + /// depth, normal, and/or motion vectors textures, among others. pub prepass_enabled: bool, /// Debugging flags that can optionally be set when constructing the renderer. pub debug_flags: RenderDebugFlags, diff --git a/crates/bevy_pbr/src/pbr_material.rs b/crates/bevy_pbr/src/pbr_material.rs index 1a858af442215..2e2829fe88320 100644 --- a/crates/bevy_pbr/src/pbr_material.rs +++ b/crates/bevy_pbr/src/pbr_material.rs @@ -257,10 +257,7 @@ pub struct StandardMaterial { /// Specular transmission is implemented as a relatively expensive screen-space effect that allows occluded objects to be seen through the material, /// with distortion and blur effects. /// - /// - [`Camera3d::screen_space_specular_transmission_steps`](bevy_core_pipeline::core_3d::Camera3d::screen_space_specular_transmission_steps) can be used to enable transmissive objects - /// to be seen through other transmissive objects, at the cost of additional draw calls and texture copies; (Use with caution!) - /// - If a simplified approximation of specular transmission using only environment map lighting is sufficient, consider setting - /// [`Camera3d::screen_space_specular_transmission_steps`](bevy_core_pipeline::core_3d::Camera3d::screen_space_specular_transmission_steps) to `0`. + /// - Requires that the camera supports specular transmission. See camera's documentation for more info. /// - If purely diffuse light transmission is needed, (i.e. “translucency”) consider using [`StandardMaterial::diffuse_transmission`] instead, /// for a much less expensive effect. /// - Specular transmission is rendered before alpha blending, so any material with [`AlphaMode::Blend`], [`AlphaMode::Premultiplied`], [`AlphaMode::Add`] or [`AlphaMode::Multiply`] @@ -1512,6 +1509,19 @@ impl Material for StandardMaterial { shader_defs.push(shader_def.into()); } } + + if cfg!(feature = "pbr_transmission_textures") { + shader_defs.push("PBR_TRANSMISSION_TEXTURES_SUPPORTED".into()); + } + if cfg!(feature = "pbr_multi_layer_material_textures") { + shader_defs.push("PBR_MULTI_LAYER_MATERIAL_TEXTURES_SUPPORTED".into()); + } + if cfg!(feature = "pbr_anisotropy_texture") { + shader_defs.push("PBR_ANISOTROPY_TEXTURE_SUPPORTED".into()); + } + if cfg!(feature = "pbr_specular_textures") { + shader_defs.push("PBR_SPECULAR_TEXTURES_SUPPORTED".into()); + } } descriptor.primitive.cull_mode = if key diff --git a/crates/bevy_render_3d/Cargo.toml b/crates/bevy_render_3d/Cargo.toml index 4ee0577e93406..88be807bcc5da 100644 --- a/crates/bevy_render_3d/Cargo.toml +++ b/crates/bevy_render_3d/Cargo.toml @@ -9,17 +9,20 @@ license = "MIT OR Apache-2.0" keywords = ["bevy"] [features] +std = ["bevy_platform_support/std", "tracing/std"] webgl = [] webgpu = [] -pbr_transmission_textures = [] -pbr_multi_layer_material_textures = [] -pbr_anisotropy_texture = [] -experimental_pbr_pcss = [] -pbr_specular_textures = [] +experimental_pcss = [] shader_format_glsl = ["bevy_render/shader_format_glsl"] trace = ["bevy_render/trace"] # Enables the meshlet renderer for dense high-poly scenes (experimental) -meshlet = ["dep:lz4_flex", "dep:range-alloc", "dep:half", "dep:bevy_tasks"] +meshlet = [ + "dep:lz4_flex", + "dep:range-alloc", + "dep:half", + "dep:thiserror", + "dep:bevy_tasks", +] # Enables processing meshes into meshlet meshes meshlet_processor = [ "meshlet", @@ -40,21 +43,18 @@ bevy_diagnostic = { path = "../bevy_diagnostic", version = "0.16.0-dev" } bevy_ecs = { path = "../bevy_ecs", version = "0.16.0-dev" } bevy_image = { path = "../bevy_image", version = "0.16.0-dev" } bevy_math = { path = "../bevy_math", version = "0.16.0-dev" } -bevy_platform_support = { path = "../bevy_platform_support", version = "0.16.0-dev", default-features = false, features = [ - "std", -] } +bevy_platform_support = { path = "../bevy_platform_support", version = "0.16.0-dev", default-features = false } bevy_reflect = { path = "../bevy_reflect", version = "0.16.0-dev" } bevy_render = { path = "../bevy_render", version = "0.16.0-dev" } bevy_tasks = { path = "../bevy_tasks", version = "0.16.0-dev", optional = true } bevy_transform = { path = "../bevy_transform", version = "0.16.0-dev" } bevy_utils = { path = "../bevy_utils", version = "0.16.0-dev" } -bevy_window = { path = "../bevy_window", version = "0.16.0-dev" } # other bitflags = "2.3" derive_more = { version = "1", default-features = false, features = ["from"] } fixedbitset = "0.5" -thiserror = { version = "2", default-features = false } +thiserror = { version = "2", default-features = false, optional = true } # meshlet lz4_flex = { version = "0.11", default-features = false, features = [ "frame", @@ -67,11 +67,10 @@ itertools = { version = "0.14", optional = true } bitvec = { version = "1", optional = true } # direct dependency required for derive macro bytemuck = { version = "1", features = ["derive", "must_cast"] } -radsort = "0.1" smallvec = "1.6" nonmax = "0.5" static_assertions = "1" -tracing = { version = "0.1", default-features = false, features = ["std"] } +tracing = { version = "0.1", default-features = false } offset-allocator = "0.2" [lints] diff --git a/crates/bevy_render_3d/src/light/directional_light.rs b/crates/bevy_render_3d/src/light/directional_light.rs index 97f5b6b9e0f5b..4128f21042e35 100644 --- a/crates/bevy_render_3d/src/light/directional_light.rs +++ b/crates/bevy_render_3d/src/light/directional_light.rs @@ -97,7 +97,7 @@ pub struct DirectionalLight { /// /// Note that soft shadows are significantly more expensive to render than /// hard shadows. - #[cfg(feature = "experimental_pbr_pcss")] + #[cfg(feature = "experimental_pcss")] pub soft_shadow_size: Option, /// Whether this directional light contributes diffuse lighting to meshes @@ -138,7 +138,7 @@ impl Default for DirectionalLight { shadow_depth_bias: Self::DEFAULT_SHADOW_DEPTH_BIAS, shadow_normal_bias: Self::DEFAULT_SHADOW_NORMAL_BIAS, affects_lightmapped_mesh_diffuse: true, - #[cfg(feature = "experimental_pbr_pcss")] + #[cfg(feature = "experimental_pcss")] soft_shadow_size: None, } } diff --git a/crates/bevy_render_3d/src/light/point_light.rs b/crates/bevy_render_3d/src/light/point_light.rs index 4f4795fb55990..15a908f5bbf7e 100644 --- a/crates/bevy_render_3d/src/light/point_light.rs +++ b/crates/bevy_render_3d/src/light/point_light.rs @@ -68,7 +68,7 @@ pub struct PointLight { /// /// Note that soft shadows are significantly more expensive to render than /// hard shadows. - #[cfg(feature = "experimental_pbr_pcss")] + #[cfg(feature = "experimental_pcss")] pub soft_shadows_enabled: bool, /// Whether this point light contributes diffuse lighting to meshes with @@ -119,7 +119,7 @@ impl Default for PointLight { shadow_depth_bias: Self::DEFAULT_SHADOW_DEPTH_BIAS, shadow_normal_bias: Self::DEFAULT_SHADOW_NORMAL_BIAS, shadow_map_near_z: Self::DEFAULT_SHADOW_MAP_NEAR_Z, - #[cfg(feature = "experimental_pbr_pcss")] + #[cfg(feature = "experimental_pcss")] soft_shadows_enabled: false, } } diff --git a/crates/bevy_render_3d/src/light/spot_light.rs b/crates/bevy_render_3d/src/light/spot_light.rs index a7cfe1b817407..4b7906a50a144 100644 --- a/crates/bevy_render_3d/src/light/spot_light.rs +++ b/crates/bevy_render_3d/src/light/spot_light.rs @@ -58,7 +58,7 @@ pub struct SpotLight { /// /// Note that soft shadows are significantly more expensive to render than /// hard shadows. - #[cfg(feature = "experimental_pbr_pcss")] + #[cfg(feature = "experimental_pcss")] pub soft_shadows_enabled: bool, /// Whether this spot light contributes diffuse lighting to meshes with @@ -135,7 +135,7 @@ impl Default for SpotLight { shadow_map_near_z: Self::DEFAULT_SHADOW_MAP_NEAR_Z, inner_angle: 0.0, outer_angle: core::f32::consts::FRAC_PI_4, - #[cfg(feature = "experimental_pbr_pcss")] + #[cfg(feature = "experimental_pcss")] soft_shadows_enabled: false, } } diff --git a/crates/bevy_render_3d/src/render/light.rs b/crates/bevy_render_3d/src/render/light.rs index eb549bd2486d4..4275a063ffcc7 100644 --- a/crates/bevy_render_3d/src/render/light.rs +++ b/crates/bevy_render_3d/src/render/light.rs @@ -174,10 +174,10 @@ pub const MAX_CASCADES_PER_LIGHT: usize = 1; #[derive(Resource, Clone)] pub struct ShadowSamplers { pub point_light_comparison_sampler: Sampler, - #[cfg(feature = "experimental_pbr_pcss")] + #[cfg(feature = "experimental_pcss")] pub point_light_linear_sampler: Sampler, pub directional_light_comparison_sampler: Sampler, - #[cfg(feature = "experimental_pbr_pcss")] + #[cfg(feature = "experimental_pcss")] pub directional_light_linear_sampler: Sampler, } @@ -201,7 +201,7 @@ impl FromWorld for ShadowSamplers { compare: Some(CompareFunction::GreaterEqual), ..base_sampler_descriptor }), - #[cfg(feature = "experimental_pbr_pcss")] + #[cfg(feature = "experimental_pcss")] point_light_linear_sampler: render_device.create_sampler(&base_sampler_descriptor), directional_light_comparison_sampler: render_device.create_sampler( &SamplerDescriptor { @@ -209,7 +209,7 @@ impl FromWorld for ShadowSamplers { ..base_sampler_descriptor }, ), - #[cfg(feature = "experimental_pbr_pcss")] + #[cfg(feature = "experimental_pcss")] directional_light_linear_sampler: render_device .create_sampler(&base_sampler_descriptor), } @@ -331,9 +331,9 @@ pub fn extract_lights( spot_light_angles: None, volumetric: volumetric_light.is_some(), affects_lightmapped_mesh_diffuse: point_light.affects_lightmapped_mesh_diffuse, - #[cfg(feature = "experimental_pbr_pcss")] + #[cfg(feature = "experimental_pcss")] soft_shadows_enabled: point_light.soft_shadows_enabled, - #[cfg(not(feature = "experimental_pbr_pcss"))] + #[cfg(not(feature = "experimental_pcss"))] soft_shadows_enabled: false, }; point_lights_values.push(( @@ -397,9 +397,9 @@ pub fn extract_lights( volumetric: volumetric_light.is_some(), affects_lightmapped_mesh_diffuse: spot_light .affects_lightmapped_mesh_diffuse, - #[cfg(feature = "experimental_pbr_pcss")] + #[cfg(feature = "experimental_pcss")] soft_shadows_enabled: spot_light.soft_shadows_enabled, - #[cfg(not(feature = "experimental_pbr_pcss"))] + #[cfg(not(feature = "experimental_pcss"))] soft_shadows_enabled: false, }, render_visible_entities, @@ -477,9 +477,9 @@ pub fn extract_lights( volumetric: volumetric_light.is_some(), affects_lightmapped_mesh_diffuse: directional_light .affects_lightmapped_mesh_diffuse, - #[cfg(feature = "experimental_pbr_pcss")] + #[cfg(feature = "experimental_pcss")] soft_shadow_size: directional_light.soft_shadow_size, - #[cfg(not(feature = "experimental_pbr_pcss"))] + #[cfg(not(feature = "experimental_pcss"))] soft_shadow_size: None, shadows_enabled: directional_light.shadows_enabled, shadow_depth_bias: directional_light.shadow_depth_bias, diff --git a/crates/bevy_render_3d/src/render/mesh.rs b/crates/bevy_render_3d/src/render/mesh.rs index 424debede9b5f..55f4cd8c99452 100644 --- a/crates/bevy_render_3d/src/render/mesh.rs +++ b/crates/bevy_render_3d/src/render/mesh.rs @@ -2344,19 +2344,6 @@ impl SpecializedMeshPipeline for MeshPipeline { vertex_attributes.push(Mesh::ATTRIBUTE_COLOR.at_shader_location(5)); } - if cfg!(feature = "pbr_transmission_textures") { - shader_defs.push("PBR_TRANSMISSION_TEXTURES_SUPPORTED".into()); - } - if cfg!(feature = "pbr_multi_layer_material_textures") { - shader_defs.push("PBR_MULTI_LAYER_MATERIAL_TEXTURES_SUPPORTED".into()); - } - if cfg!(feature = "pbr_anisotropy_texture") { - shader_defs.push("PBR_ANISOTROPY_TEXTURE_SUPPORTED".into()); - } - if cfg!(feature = "pbr_specular_textures") { - shader_defs.push("PBR_SPECULAR_TEXTURES_SUPPORTED".into()); - } - let mut bind_group_layout = vec![self.get_view_layout(key.into()).clone()]; if key.msaa_samples() > 1 { @@ -2481,7 +2468,7 @@ impl SpecializedMeshPipeline for MeshPipeline { #[cfg(all(feature = "webgl", target_arch = "wasm32", not(feature = "webgpu")))] shader_defs.push("WEBGL2".into()); - #[cfg(feature = "experimental_pbr_pcss")] + #[cfg(feature = "experimental_pcss")] shader_defs.push("PCSS_SAMPLERS_AVAILABLE".into()); if key.contains(MeshPipelineKey::TONEMAP_IN_SHADER) { diff --git a/crates/bevy_render_3d/src/render/mesh_view_bindings.rs b/crates/bevy_render_3d/src/render/mesh_view_bindings.rs index 8e231886bae1e..6c6a541a8065e 100644 --- a/crates/bevy_render_3d/src/render/mesh_view_bindings.rs +++ b/crates/bevy_render_3d/src/render/mesh_view_bindings.rs @@ -233,7 +233,7 @@ fn layout_entries( // Point Shadow Texture Array Comparison Sampler (3, sampler(SamplerBindingType::Comparison)), // Point Shadow Texture Array Linear Sampler - #[cfg(feature = "experimental_pbr_pcss")] + #[cfg(feature = "experimental_pcss")] (4, sampler(SamplerBindingType::Filtering)), // Directional Shadow Texture Array ( @@ -250,7 +250,7 @@ fn layout_entries( // Directional Shadow Texture Array Comparison Sampler (6, sampler(SamplerBindingType::Comparison)), // Directional Shadow Texture Array Linear Sampler - #[cfg(feature = "experimental_pbr_pcss")] + #[cfg(feature = "experimental_pcss")] (7, sampler(SamplerBindingType::Filtering)), // PointLights ( @@ -592,11 +592,11 @@ pub fn prepare_mesh_view_bind_groups( (1, light_binding.clone()), (2, &shadow_bindings.point_light_depth_texture_view), (3, &shadow_samplers.point_light_comparison_sampler), - #[cfg(feature = "experimental_pbr_pcss")] + #[cfg(feature = "experimental_pcss")] (4, &shadow_samplers.point_light_linear_sampler), (5, &shadow_bindings.directional_light_depth_texture_view), (6, &shadow_samplers.directional_light_comparison_sampler), - #[cfg(feature = "experimental_pbr_pcss")] + #[cfg(feature = "experimental_pcss")] (7, &shadow_samplers.directional_light_linear_sampler), (8, clusterable_objects_binding.clone()), ( diff --git a/docs/cargo_features.md b/docs/cargo_features.md index da46243526fbe..c7eb09f17f698 100644 --- a/docs/cargo_features.md +++ b/docs/cargo_features.md @@ -79,7 +79,7 @@ The default feature set enables most of the expected features of a game engine, |detailed_trace|Enable detailed trace event logging. These trace events are expensive even when off, thus they require compile time opt-in| |dynamic_linking|Force dynamic linking, which improves iterative compile times| |embedded_watcher|Enables watching in memory asset providers for Bevy Asset hot-reloading| -|experimental_pbr_pcss|Enable support for PCSS, at the risk of blowing past the global, per-shader sampler limit on older/lower-end GPUs| +|experimental_pcss|Enable support for PCSS, at the risk of blowing past the global, per-shader sampler limit on older/lower-end GPUs| |exr|EXR image format support| |ff|Farbfeld image format support| |file_watcher|Enables watching the filesystem for Bevy Asset hot-reloading|