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.
1import package::{
2 prepass::utils as prepass_utils,
3 render::{
4 pbr_types::STANDARD_MATERIAL_FLAGS_UNLIT_BIT,
5 pbr_functions,
6 pbr_lighting as lighting,
7 mesh_view_bindings::{deferred_prepass_texture, view},
8 },
9 deferred::{
10 functions::pbr_input_from_deferred_gbuffer,
11 types::unpack_unorm3x4_plus_unorm_20_,
12 },
13};
15@if(SCREEN_SPACE_AMBIENT_OCCLUSION) import package::render::mesh_view_bindings::screen_space_ambient_occlusion_texture;
16@if(SCREEN_SPACE_AMBIENT_OCCLUSION) import package::ssao::utils::ssao_multibounce;
18struct FullscreenVertexOutput {
19 @builtin(position)
20 position: vec4<f32>,
21 @location(0)
22 uv: vec2<f32>,
23};
25struct PbrDeferredLightingDepthId {
26 depth_id: u32, // limited to u8
27 @if(SIXTEEN_BYTE_ALIGNMENT)
28 // WebGL2 structs must be 16 byte aligned.
29 _webgl2_padding_0: f32,
30 @if(SIXTEEN_BYTE_ALIGNMENT)
31 _webgl2_padding_1: f32,
32 @if(SIXTEEN_BYTE_ALIGNMENT)
33 _webgl2_padding_2: f32,
35@group(2) @binding(0)
36var<uniform> depth_id: PbrDeferredLightingDepthId;
38@vertex
39fn vertex(@builtin(vertex_index) vertex_index: u32) -> FullscreenVertexOutput {
40 // See the full screen vertex shader for explanation above for how this works.
41 let uv = vec2<f32>(f32(vertex_index >> 1u), f32(vertex_index & 1u)) * 2.0;
42 // Depth is stored as unorm, so we are dividing the u8 depth_id by 255.0 here.
43 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);
45 return FullscreenVertexOutput(clip_position, uv);
48@fragment
49fn fragment(in: FullscreenVertexOutput) -> @location(0) vec4<f32> {
50 var frag_coord = vec4(in.position.xy, 0.0, 0.0);
52 let deferred_data = textureLoad(deferred_prepass_texture, vec2<i32>(frag_coord.xy), 0);
54 @if(WEBGL2)
55 frag_coord.z = unpack_unorm3x4_plus_unorm_20_(deferred_data.b).w;
56 @elif(DEPTH_PREPASS)
57 frag_coord.z = prepass_utils::prepass_depth(in.position, 0u);
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@if(SCREEN_SPACE_AMBIENT_OCCLUSION) {
66 let ssao_tex_pos = vec2<i32>(in.position.xy - view.viewport.xy);
67 let ssao = textureLoad(screen_space_ambient_occlusion_texture, ssao_tex_pos, 0i).r;
68 let ssao_multibounce = ssao_multibounce(ssao, pbr_input.material.base_color.rgb);
69 pbr_input.diffuse_occlusion = min(pbr_input.diffuse_occlusion, ssao_multibounce);
71 // Neubelt and Pettineo 2013, "Crafting a Next-gen Material Pipeline for The Order: 1886"
72 let NdotV = max(dot(pbr_input.N, pbr_input.V), 0.0001);
73 var perceptual_roughness: f32 = pbr_input.material.perceptual_roughness;
74 let roughness = lighting::perceptualRoughnessToRoughness(perceptual_roughness);
75 // Use SSAO to estimate the specular occlusion.
76 // Lagarde and Rousiers 2014, "Moving Frostbite to Physically Based Rendering"
77 pbr_input.specular_occlusion = saturate(pow(NdotV + ssao, exp2(-16.0 * roughness - 1.0)) - 1.0 + ssao);
80 output_color = pbr_functions::apply_pbr_lighting(pbr_input);
81 } else {
82 output_color = pbr_input.material.base_color;
83 }
85 output_color = pbr_functions::main_pass_post_lighting_processing(pbr_input, output_color);
87 return output_color;
Contents