diff --git a/crates/bevy_pbr/src/deferred/mod.rs b/crates/bevy_pbr/src/deferred/mod.rs index 41766372d9f36..a6c66a2fedaf5 100644 --- a/crates/bevy_pbr/src/deferred/mod.rs +++ b/crates/bevy_pbr/src/deferred/mod.rs @@ -349,6 +349,22 @@ impl SpecializedRenderPipeline for DeferredLightingLayout { shader_defs.push("MULTIPLE_LIGHTMAPS_IN_ARRAY".into()); } + if cfg!(feature = "pbr_multi_layer_material_textures") { + shader_defs.push("PBR_MULTI_LAYER_MATERIAL_TEXTURES_SUPPORTED".into()); + } + + if cfg!(feature = "pbr_transmission_textures") { + shader_defs.push("PBR_TRANSMISSION_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()); + } + #[cfg(all(feature = "webgl", target_arch = "wasm32", not(feature = "webgpu")))] shader_defs.push("SIXTEEN_BYTE_ALIGNMENT".into()); diff --git a/crates/bevy_pbr/src/pbr_material.rs b/crates/bevy_pbr/src/pbr_material.rs index c1d08acc282e2..6369e8cca1b89 100644 --- a/crates/bevy_pbr/src/pbr_material.rs +++ b/crates/bevy_pbr/src/pbr_material.rs @@ -1477,6 +1477,17 @@ impl Material for StandardMaterial { StandardMaterialKey::ANISOTROPY, "STANDARD_MATERIAL_ANISOTROPY", ), + ] { + if key.bind_group_data.contains(flags) { + shader_defs.push(shader_def.into()); + } + } + + if cfg!(feature = "pbr_multi_layer_material_textures") { + shader_defs.push("PBR_MULTI_LAYER_MATERIAL_TEXTURES_SUPPORTED".into()); + } + + for (flags, shader_def) in [ ( StandardMaterialKey::BASE_COLOR_UV, "STANDARD_MATERIAL_BASE_COLOR_UV_B", diff --git a/crates/bevy_pbr/src/render/mesh_view_types.wgsl b/crates/bevy_pbr/src/render/mesh_view_types.wgsl index 112556ee1eb76..5313b01e0169e 100644 --- a/crates/bevy_pbr/src/render/mesh_view_types.wgsl +++ b/crates/bevy_pbr/src/render/mesh_view_types.wgsl @@ -161,6 +161,7 @@ struct ScreenSpaceReflectionsSettings { linear_march_exponent: f32, bisection_steps: u32, use_secant: u32, + samples: u32, }; struct EnvironmentMapUniform { diff --git a/crates/bevy_pbr/src/render/pbr_ambient.wgsl b/crates/bevy_pbr/src/render/pbr_ambient.wgsl index 7b174da35c9db..c93548cff2991 100644 --- a/crates/bevy_pbr/src/render/pbr_ambient.wgsl +++ b/crates/bevy_pbr/src/render/pbr_ambient.wgsl @@ -15,15 +15,20 @@ fn ambient_light( diffuse_color: vec3, specular_color: vec3, perceptual_roughness: f32, - occlusion: vec3, + diffuse_occlusion: vec3, + specular_occlusion: f32, ) -> vec3 { - let diffuse_ambient = EnvBRDFApprox(diffuse_color, F_AB(1.0, NdotV)); - let specular_ambient = EnvBRDFApprox(specular_color, F_AB(perceptual_roughness, NdotV)); - + let F_ab_diffuse = F_AB(1.0, NdotV); + let diffuse_ambient = diffuse_color * (F_ab_diffuse.x + F_ab_diffuse.y) * diffuse_occlusion; + let Fr = max(vec3(1.0 - perceptual_roughness), specular_color) - specular_color; + let kS = specular_color + Fr * pow(1.0 - NdotV, 5.0); + let F_ab_vals = F_AB(perceptual_roughness, NdotV); + let Ess = F_ab_vals.x + F_ab_vals.y; // 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))); + let pre_baked_specular_occlusion = saturate(dot(specular_color, vec3(50.0 * 0.33))); + let specular_ambient = kS * Ess * pre_baked_specular_occlusion * specular_occlusion; - return (diffuse_ambient + specular_ambient * specular_occlusion) * lights.ambient_color.rgb * occlusion; + return (diffuse_ambient + specular_ambient) * lights.ambient_color.rgb; } diff --git a/crates/bevy_pbr/src/render/pbr_functions.wgsl b/crates/bevy_pbr/src/render/pbr_functions.wgsl index 2c862958dd223..72430fbfd9fef 100644 --- a/crates/bevy_pbr/src/render/pbr_functions.wgsl +++ b/crates/bevy_pbr/src/render/pbr_functions.wgsl @@ -567,7 +567,7 @@ fn apply_pbr_lighting( // 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)); + 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), 1.0); #endif // Diffuse indirect lighting can come from a variety of sources. The @@ -613,23 +613,23 @@ fn apply_pbr_lighting( let use_ssr = false; #endif // SCREEN_SPACE_REFLECTIONS - if (!use_ssr) { #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; + 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; + 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, - ); + let environment_light = environment_map::environment_map_light( + environment_map_lighting_input, + &clusterable_object_index_ranges, + found_diffuse_indirect, + ); - indirect_light += environment_light.diffuse * diffuse_occlusion + - environment_light.specular * specular_occlusion; + indirect_light += environment_light.diffuse * diffuse_occlusion; + if (!use_ssr) { + indirect_light += environment_light.specular * specular_occlusion; } #endif // ENVIRONMENT_MAP @@ -642,7 +642,7 @@ fn apply_pbr_lighting( let enable_ambient = true; #endif // LIGHTMAP if (enable_ambient) { - indirect_light += ambient::ambient_light(in.world_position, in.N, in.V, NdotV, diffuse_color, F0, perceptual_roughness, diffuse_occlusion); + indirect_light += ambient::ambient_light(in.world_position, in.N, in.V, NdotV, diffuse_color, F0, perceptual_roughness, diffuse_occlusion, specular_occlusion); } // we'll use the specular component of the transmitted environment diff --git a/crates/bevy_pbr/src/ssr/mod.rs b/crates/bevy_pbr/src/ssr/mod.rs index 7bd9d02c529de..2bc80330a10ad 100644 --- a/crates/bevy_pbr/src/ssr/mod.rs +++ b/crates/bevy_pbr/src/ssr/mod.rs @@ -125,6 +125,12 @@ pub struct ScreenSpaceReflections { /// line-line intersection between the ray approach rate and the surface /// gradient. pub use_secant: bool, + + /// The number of samples to take per pixel. + /// + /// Higher values result in higher-quality reflections, especially for + /// rough materials, but take more GPU time. + pub samples: u32, } /// A version of [`ScreenSpaceReflections`] for upload to the GPU. @@ -140,6 +146,7 @@ pub struct ScreenSpaceReflectionsUniform { bisection_steps: u32, /// A boolean converted to a `u32`. use_secant: u32, + samples: u32, } /// The node in the render graph that traces screen space reflections. @@ -180,6 +187,7 @@ pub struct ScreenSpaceReflectionsPipelineKey { is_hdr: bool, has_environment_maps: bool, has_atmosphere: bool, + has_ssao: bool, } impl Plugin for ScreenSpaceReflectionsPlugin { @@ -240,12 +248,13 @@ impl Default for ScreenSpaceReflections { // . fn default() -> Self { Self { - perceptual_roughness_threshold: 0.1, + perceptual_roughness_threshold: 1.0, linear_steps: 16, bisection_steps: 4, use_secant: true, thickness: 0.25, linear_march_exponent: 1.0, + samples: 1, } } } @@ -424,6 +433,7 @@ pub fn prepare_ssr_pipelines( Has, Has, Has, + Has, ), ( With, @@ -439,6 +449,7 @@ pub fn prepare_ssr_pipelines( has_normal_prepass, has_motion_vector_prepass, has_atmosphere, + has_ssao, ) in &views { // SSR is only supported in the deferred pipeline, which has no MSAA @@ -465,6 +476,7 @@ pub fn prepare_ssr_pipelines( is_hdr: extracted_view.hdr, has_environment_maps, has_atmosphere, + has_ssao, }, ); @@ -555,6 +567,28 @@ impl SpecializedRenderPipeline for ScreenSpaceReflectionsPipeline { #[cfg(not(target_arch = "wasm32"))] shader_defs.push("USE_DEPTH_SAMPLERS".into()); + if key.has_ssao { + shader_defs.push("SCREEN_SPACE_AMBIENT_OCCLUSION".into()); + } + + if cfg!(feature = "pbr_multi_layer_material_textures") { + shader_defs.push("PBR_MULTI_LAYER_MATERIAL_TEXTURES_SUPPORTED".into()); + } + + if cfg!(feature = "pbr_transmission_textures") { + shader_defs.push("PBR_TRANSMISSION_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()); + } + + shader_defs.push("STANDARD_MATERIAL_CLEARCOAT".into()); + RenderPipelineDescriptor { label: Some("SSR pipeline".into()), layout, @@ -587,6 +621,7 @@ impl From for ScreenSpaceReflectionsUniform { linear_march_exponent: settings.linear_march_exponent, bisection_steps: settings.bisection_steps, use_secant: settings.use_secant as u32, + samples: settings.samples, } } } diff --git a/crates/bevy_pbr/src/ssr/ssr.wgsl b/crates/bevy_pbr/src/ssr/ssr.wgsl index d646ac69febf9..34567b3fae4ec 100644 --- a/crates/bevy_pbr/src/ssr/ssr.wgsl +++ b/crates/bevy_pbr/src/ssr/ssr.wgsl @@ -5,13 +5,19 @@ #import bevy_core_pipeline::fullscreen_vertex_shader::FullscreenVertexOutput #import bevy_pbr::{ clustered_forward, + clustered_forward::{fragment_cluster_index, unpack_clusterable_object_index_ranges}, lighting, - lighting::{LAYER_BASE, LAYER_CLEARCOAT}, - mesh_view_bindings::{view, depth_prepass_texture, deferred_prepass_texture, ssr_settings}, + lighting::{LAYER_BASE, LAYER_CLEARCOAT, sample_visible_ggx, F_AB, perceptualRoughnessToRoughness, LightingInput}, + mesh_view_bindings, + mesh_view_bindings::{view, depth_prepass_texture, deferred_prepass_texture, ssr_settings, globals, screen_space_ambient_occlusion_texture, light_probes}, pbr_deferred_functions::pbr_input_from_deferred_gbuffer, pbr_deferred_types, pbr_functions, + pbr_functions::{calculate_diffuse_color, calculate_F0}, + light_probe::query_light_probe, + environment_map::{compute_radiances, environment_map_light_clearcoat, EnvironmentMapLight}, prepass_utils, + ssao_utils::ssao_multibounce, raymarch::{ depth_ray_march_from_cs, depth_ray_march_march, @@ -19,6 +25,7 @@ depth_ray_march_to_ws_dir, }, utils, + utils::interleaved_gradient_noise, view_transformations::{ depth_ndc_to_view_z, frag_coord_to_ndc, @@ -33,6 +40,7 @@ #ifdef ENVIRONMENT_MAP #import bevy_pbr::environment_map +#import bevy_pbr::environment_map::environment_map_light #endif // The texture representing the color framebuffer. @@ -56,8 +64,10 @@ // // * `P_world`: The current position in world space. // +// * `jitter`: The jitter value for the raymarcher. +// // [1]: https://lettier.github.io/3d-game-shaders-for-beginners/screen-space-reflection.html -fn evaluate_ssr(R_world: vec3, P_world: vec3) -> vec4 { +fn evaluate_ssr(R_world: vec3, P_world: vec3, jitter: f32) -> vec4 { let depth_size = vec2(textureDimensions(depth_prepass_texture)); var raymarch = depth_ray_march_new_from_depth(depth_size); @@ -67,7 +77,7 @@ fn evaluate_ssr(R_world: vec3, P_world: vec3) -> vec4 { raymarch.bisection_steps = ssr_settings.bisection_steps; raymarch.use_secant = ssr_settings.use_secant != 0u; raymarch.depth_thickness_linear_z = ssr_settings.thickness; - raymarch.jitter = 1.0; // Disable jitter for now. + raymarch.jitter = jitter; raymarch.march_behind_surfaces = false; let raymarch_result = depth_ray_march_march(&raymarch); @@ -85,12 +95,27 @@ fn evaluate_ssr(R_world: vec3, P_world: vec3) -> vec4 { fn fragment(in: FullscreenVertexOutput) -> @location(0) vec4 { // Sample the depth. var frag_coord = in.position; - frag_coord.z = prepass_utils::prepass_depth(in.position, 0u); +#ifdef DEPTH_PREPASS + frag_coord.z = textureLoad(depth_prepass_texture, vec2(in.position.xy), 0); +#endif // Load the G-buffer data. let fragment = textureLoad(color_texture, vec2(frag_coord.xy), 0); let gbuffer = textureLoad(deferred_prepass_texture, vec2(frag_coord.xy), 0); - let pbr_input = pbr_input_from_deferred_gbuffer(frag_coord, gbuffer); + var pbr_input = pbr_input_from_deferred_gbuffer(frag_coord, gbuffer); + +#ifdef SCREEN_SPACE_AMBIENT_OCCLUSION + let ssao = textureLoad(screen_space_ambient_occlusion_texture, vec2(frag_coord.xy), 0).r; + let ssao_multibounce = ssao_multibounce(ssao, pbr_input.material.base_color.rgb); + pbr_input.diffuse_occlusion = min(pbr_input.diffuse_occlusion, ssao_multibounce); + + // Neubelt and Pettineo 2013, "Crafting a Next-gen Material Pipeline for The Order: 1886" + let NdotV_ao = max(dot(pbr_input.N, pbr_input.V), 0.0001); + let roughness_ao = perceptualRoughnessToRoughness(pbr_input.material.perceptual_roughness); + // Use SSAO to estimate the specular occlusion. + // Lagarde and Rousiers 2014, "Moving Frostbite to Physically Based Rendering" + pbr_input.specular_occlusion = saturate(pow(NdotV_ao + ssao, exp2(-16.0 * roughness_ao - 1.0)) - 1.0 + ssao); +#endif // Don't do anything if the surface is too rough, since we can't blur or do // temporal accumulation yet. @@ -100,18 +125,90 @@ fn fragment(in: FullscreenVertexOutput) -> @location(0) vec4 { } // Unpack the PBR input. - var specular_occlusion = pbr_input.specular_occlusion; + let base_color = pbr_input.material.base_color.rgb; + let metallic = pbr_input.material.metallic; + let reflectance = pbr_input.material.reflectance; + let specular_transmission = pbr_input.material.specular_transmission; + let diffuse_transmission = pbr_input.material.diffuse_transmission; + let diffuse_occlusion = pbr_input.diffuse_occlusion; let world_position = pbr_input.world_position.xyz; let N = pbr_input.N; let V = pbr_input.V; - // Calculate the reflection vector. - let R = reflect(-V, N); + let roughness = perceptualRoughnessToRoughness(perceptual_roughness); // Do the raymarching. - let ssr_specular = evaluate_ssr(R, world_position); - var indirect_light = ssr_specular.rgb; - specular_occlusion *= ssr_specular.a; + var ssr_specular = vec4(0.0); + let noise = interleaved_gradient_noise(frag_coord.xy, globals.frame_count); + + var sample_count = 0u; + for (var i: u32 = 0u; i < ssr_settings.samples; i = i + 1u) { + sample_count += 1u; + + // Adaptive sampling: if the surface is rough, we only take one sample for now + // to save performance, as we don't have a denoiser yet anyway. + if (perceptual_roughness > 0.4 && i > 0u) { + break; + } + + var R = reflect(-V, N); + if (roughness > 0.0) { + let xi = vec2( + fract(noise + f32(i) * 0.61803398875), + fract(noise * 0.61803398875 + f32(i)) + ); + R = sample_visible_ggx(xi, roughness, N, V); + } + + let sample_jitter = fract(noise + f32(i) * 0.61803398875); + let ssr_sample = evaluate_ssr(R, world_position, sample_jitter); + ssr_specular += ssr_sample; + + // If the first sample hit nothing (sky), we often don't want to keep tracing + // because it's expensive and likely to hit nothing again for moderately smooth surfaces. + if (ssr_sample.a > 0.9 && i == 0u && perceptual_roughness < 0.2) { + // For smooth surfaces, we expect most rays to follow a similar path. + // If the first one missed, the others probably will too. + break; + } + } + ssr_specular /= f32(sample_count); + + // Calculate various values needed for both SSR weighting and environment mapping. + let diffuse_color = calculate_diffuse_color( + base_color, + metallic, + specular_transmission, + diffuse_transmission + ); + let NdotV = max(dot(N, V), 0.0001); + let F_ab = F_AB(perceptual_roughness, NdotV); + let F0 = calculate_F0(base_color, metallic, reflectance); + + // 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(F0, vec3(50.0 * 0.33))); + + let Fr = max(vec3(1.0 - perceptual_roughness), F0) - F0; + let kS = F0 + Fr * pow(1.0 - NdotV, 5.0); + let Ess = F_ab.x + F_ab.y; + let FssEss = kS * Ess * specular_occlusion; + + // Multiscattering approximation: https://www.jcgt.org/published/0008/01/03/paper.pdf + // Useful reference: https://bruop.github.io/ibl + let Ems = 1.0 - Ess; + let Favg = F0 + (1.0 - F0) / 21.0; + let Fms = FssEss * Favg / (1.0 - Ems * Favg); + let FmsEms = Fms * Ems; + let Edss = 1.0 - (FssEss + FmsEms); + let kD = diffuse_color * Edss; + + // SSR specular part. + // + // Note that we don't multiply by `view.exposure` here because the sampled + // `ssr_specular.rgb` is already exposed. + var indirect_light = ssr_specular.rgb * FssEss * pbr_input.specular_occlusion; // Sample the environment map if necessary. // @@ -119,43 +216,24 @@ fn fragment(in: FullscreenVertexOutput) -> @location(0) vec4 { // the ray missed. Otherwise, it only takes the diffuse part. // // TODO: Merge this with the duplicated code in `apply_pbr_lighting`. + var env_specular_weight = pbr_input.specular_occlusion * ssr_specular.a; #ifdef ENVIRONMENT_MAP - // Unpack values required for environment mapping. - let base_color = pbr_input.material.base_color.rgb; - let metallic = pbr_input.material.metallic; - let reflectance = pbr_input.material.reflectance; - let specular_transmission = pbr_input.material.specular_transmission; - let diffuse_transmission = pbr_input.material.diffuse_transmission; - let diffuse_occlusion = pbr_input.diffuse_occlusion; - #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 = pbr_input.material.clearcoat; let clearcoat_perceptual_roughness = pbr_input.material.clearcoat_perceptual_roughness; - let clearcoat_roughness = lighting::perceptualRoughnessToRoughness(clearcoat_perceptual_roughness); + let clearcoat_roughness = perceptualRoughnessToRoughness(clearcoat_perceptual_roughness); let clearcoat_N = pbr_input.clearcoat_N; let clearcoat_NdotV = max(dot(clearcoat_N, pbr_input.V), 0.0001); let clearcoat_R = reflect(-pbr_input.V, clearcoat_N); #endif // STANDARD_MATERIAL_CLEARCOAT - // Calculate various other values needed for environment mapping. - let roughness = lighting::perceptualRoughnessToRoughness(perceptual_roughness); - let diffuse_color = pbr_functions::calculate_diffuse_color( - base_color, - metallic, - specular_transmission, - diffuse_transmission - ); - let NdotV = max(dot(N, V), 0.0001); - let F_ab = lighting::F_AB(perceptual_roughness, NdotV); - let F0 = pbr_functions::calculate_F0(base_color, metallic, reflectance); - // Pack all the values into a structure. - var lighting_input: lighting::LightingInput; + var lighting_input: LightingInput; lighting_input.layers[LAYER_BASE].NdotV = NdotV; lighting_input.layers[LAYER_BASE].N = N; - lighting_input.layers[LAYER_BASE].R = R; + lighting_input.layers[LAYER_BASE].R = reflect(-V, N); // Use ideal reflection for probes lighting_input.layers[LAYER_BASE].perceptual_roughness = perceptual_roughness; lighting_input.layers[LAYER_BASE].roughness = roughness; lighting_input.P = world_position.xyz; @@ -174,19 +252,55 @@ fn fragment(in: FullscreenVertexOutput) -> @location(0) vec4 { // Determine which cluster we're in. We'll need this to find the right // reflection probe. - let cluster_index = clustered_forward::fragment_cluster_index( + let cluster_index = fragment_cluster_index( frag_coord.xy, frag_coord.z, false); var clusterable_object_index_ranges = - clustered_forward::unpack_clusterable_object_index_ranges(cluster_index); + unpack_clusterable_object_index_ranges(cluster_index); + + // Search for a reflection probe that contains the fragment. + var query_result = query_light_probe( + world_position, + /*is_irradiance_volume=*/ false, + &clusterable_object_index_ranges, + ); - // Sample the environment map. - let environment_light = environment_map::environment_map_light( - &lighting_input, &clusterable_object_index_ranges, false); + // If we didn't find a reflection probe, use the view environment map if applicable. + if (query_result.texture_index < 0) { + query_result.texture_index = light_probes.view_cubemap_index; + query_result.intensity = light_probes.intensity_for_view; + query_result.affects_lightmapped_mesh_diffuse = + light_probes.view_environment_map_affects_lightmapped_mesh_diffuse != 0u; + } + + if (query_result.texture_index >= 0) { + let radiances = compute_radiances( + lighting_input.layers[LAYER_BASE], + &clusterable_object_index_ranges, + world_position, + false, + ); - // Accumulate the environment map light. - indirect_light += view.exposure * - (environment_light.diffuse * diffuse_occlusion + - environment_light.specular * specular_occlusion); + // We only add radiance (specular) if SSR missed. + // Diffuse (irradiance) was already added in the main pass. + indirect_light += view.exposure * + radiances.radiance * FssEss * env_specular_weight; + +#ifdef STANDARD_MATERIAL_CLEARCOAT + // Composite clearcoat environment map lighting if present. + var env_light: EnvironmentMapLight; + env_light.diffuse = (FmsEms + kD) * radiances.irradiance; + env_light.specular = radiances.radiance * FssEss; + + environment_map_light_clearcoat( + &env_light, + &lighting_input, + &clusterable_object_index_ranges, + false, + ); + // Note: we need to handle clearcoat for SSR too, but for now we fallback to env map. + // This is a complex area as SSR currently only traces one layer. +#endif + } #endif // Write the results. diff --git a/examples/3d/clearcoat.rs b/examples/3d/clearcoat.rs index 613e95d4c62ea..7b81060543a30 100644 --- a/examples/3d/clearcoat.rs +++ b/examples/3d/clearcoat.rs @@ -19,6 +19,7 @@ use std::f32::consts::PI; +use bevy::pbr::{DefaultOpaqueRendererMethod, ScreenSpaceReflections}; use bevy::{ color::palettes::css::{BLUE, GOLD, WHITE}, core_pipeline::{tonemapping::Tonemapping::AcesFitted, Skybox}, @@ -50,6 +51,7 @@ struct ExampleSphere; pub fn main() { App::new() .init_resource::() + .insert_resource(DefaultOpaqueRendererMethod::deferred()) .add_plugins(DefaultPlugins) .add_systems(Startup, setup) .add_systems(Update, animate_light) @@ -198,6 +200,10 @@ fn spawn_camera(commands: &mut Commands, asset_server: &AssetServer) { ..default() }), Transform::from_xyz(0.0, 0.0, 10.0), + ScreenSpaceReflections { + samples: 1, + ..default() + }, AcesFitted, )) .insert(Skybox { diff --git a/examples/3d/deferred_rendering.rs b/examples/3d/deferred_rendering.rs index ff3656d7a6ecb..0dcafa7386cbd 100644 --- a/examples/3d/deferred_rendering.rs +++ b/examples/3d/deferred_rendering.rs @@ -13,6 +13,7 @@ use bevy::{ pbr::{DefaultOpaqueRendererMethod, OpaqueRendererMethod}, prelude::*, }; +use bevy::pbr::ScreenSpaceReflections; fn main() { App::new() @@ -53,6 +54,7 @@ fn setup( DepthPrepass, MotionVectorPrepass, DeferredPrepass, + ScreenSpaceReflections::default(), Fxaa::default(), )); diff --git a/examples/3d/ssr.rs b/examples/3d/ssr.rs index 9b98a01ca418e..95eb8ea60de49 100644 --- a/examples/3d/ssr.rs +++ b/examples/3d/ssr.rs @@ -2,6 +2,7 @@ use std::ops::Range; +use bevy::pbr::ScreenSpaceAmbientOcclusion; use bevy::{ anti_alias::fxaa::Fxaa, color::palettes::css::{BLACK, WHITE}, @@ -245,7 +246,11 @@ fn spawn_camera(commands: &mut Commands, asset_server: &AssetServer) { brightness: 5000.0, ..default() }) - .insert(ScreenSpaceReflections::default()) + .insert(ScreenSpaceReflections { + samples: 1, + ..default() + }) + .insert(ScreenSpaceAmbientOcclusion::default()) .insert(Fxaa::default()); } diff --git a/examples/tools/scene_viewer/main.rs b/examples/tools/scene_viewer/main.rs index 1a87c8072e234..b23ab9bfbcc23 100644 --- a/examples/tools/scene_viewer/main.rs +++ b/examples/tools/scene_viewer/main.rs @@ -9,6 +9,7 @@ //! If you want to hot reload asset changes, enable the `file_watcher` cargo feature. use argh::FromArgs; +use bevy::pbr::ScreenSpaceReflections; use bevy::{ asset::UnapprovedPathMode, camera::primitives::{Aabb, Sphere}, @@ -211,6 +212,7 @@ fn setup_scene_after_load( rotation: args.rotation(), ..default() }, + ScreenSpaceReflections::default(), camera_controller, ));