Search across packages, versions, files, declarations, and comments. Use multiple terms to narrow results (AND), and add @vertex, @fragment, or @compute to filter by shader stage.
1#import bevy_pbr::{
2 prepass_utils,
3 pbr_types::STANDARD_MATERIAL_FLAGS_UNLIT_BIT,
4 pbr_functions,
5 pbr_deferred_functions::pbr_input_from_deferred_gbuffer,
6 pbr_deferred_types::unpack_unorm3x4_plus_unorm_20_,
7 lighting,
8 mesh_view_bindings::deferred_prepass_texture,
9}
11#ifdef SCREEN_SPACE_AMBIENT_OCCLUSION
12#import bevy_pbr::mesh_view_bindings::screen_space_ambient_occlusion_texture
13#import bevy_pbr::ssao_utils::ssao_multibounce
14#endif
16struct FullscreenVertexOutput {
17 @builtin(position)
18 position: vec4<f32>,
19 @location(0)
20 uv: vec2<f32>,
21};
23struct PbrDeferredLightingDepthId {
24 depth_id: u32, // limited to u8
25#ifdef SIXTEEN_BYTE_ALIGNMENT
26 // WebGL2 structs must be 16 byte aligned.
27 _webgl2_padding_0: f32,
28 _webgl2_padding_1: f32,
29 _webgl2_padding_2: f32,
30#endif
32@group(2) @binding(0)
33var<uniform> depth_id: PbrDeferredLightingDepthId;
35@vertex
36fn vertex(@builtin(vertex_index) vertex_index: u32) -> FullscreenVertexOutput {
37 // See the full screen vertex shader for explanation above for how this works.
38 let uv = vec2<f32>(f32(vertex_index >> 1u), f32(vertex_index & 1u)) * 2.0;
39 // Depth is stored as unorm, so we are dividing the u8 depth_id by 255.0 here.
40 let clip_position = vec4<f32>(uv * vec2<f32>(2.0, -2.0) + vec2<f32>(-1.0, 1.0), f32(depth_id.depth_id) / 255.0, 1.0);
42 return FullscreenVertexOutput(clip_position, uv);
45@fragment
46fn fragment(in: FullscreenVertexOutput) -> @location(0) vec4<f32> {
47 var frag_coord = vec4(in.position.xy, 0.0, 0.0);
49 let deferred_data = textureLoad(deferred_prepass_texture, vec2<i32>(frag_coord.xy), 0);
51#ifdef WEBGL2
52 frag_coord.z = unpack_unorm3x4_plus_unorm_20_(deferred_data.b).w;
53#else
54#ifdef DEPTH_PREPASS
55 frag_coord.z = prepass_utils::prepass_depth(in.position, 0u);
56#endif
57#endif
59 var pbr_input = pbr_input_from_deferred_gbuffer(frag_coord, deferred_data);
60 var output_color = vec4(0.0);
62 // NOTE: Unlit bit not set means == 0 is true, so the true case is if lit
63 if ((pbr_input.material.flags & STANDARD_MATERIAL_FLAGS_UNLIT_BIT) == 0u) {
65#ifdef SCREEN_SPACE_AMBIENT_OCCLUSION
66 let ssao = textureLoad(screen_space_ambient_occlusion_texture, vec2<i32>(in.position.xy), 0i).r;
67 let ssao_multibounce = ssao_multibounce(ssao, pbr_input.material.base_color.rgb);
68 pbr_input.diffuse_occlusion = min(pbr_input.diffuse_occlusion, ssao_multibounce);
70 // Neubelt and Pettineo 2013, "Crafting a Next-gen Material Pipeline for The Order: 1886"
71 let NdotV = max(dot(pbr_input.N, pbr_input.V), 0.0001);
72 var perceptual_roughness: f32 = pbr_input.material.perceptual_roughness;
73 let roughness = lighting::perceptualRoughnessToRoughness(perceptual_roughness);
74 // Use SSAO to estimate the specular occlusion.
75 // Lagarde and Rousiers 2014, "Moving Frostbite to Physically Based Rendering"
76 pbr_input.specular_occlusion = saturate(pow(NdotV + ssao, exp2(-16.0 * roughness - 1.0)) - 1.0 + ssao);
77#endif // SCREEN_SPACE_AMBIENT_OCCLUSION
79 output_color = pbr_functions::apply_pbr_lighting(pbr_input);
80 } else {
81 output_color = pbr_input.material.base_color;
82 }
84 output_color = pbr_functions::main_pass_post_lighting_processing(pbr_input, output_color);
86 return output_color;
Contents