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#define_import_path bevy_pbr::pbr_deferred_functions
3#import bevy_pbr::{
4 pbr_types::{PbrInput, pbr_input_new, STANDARD_MATERIAL_FLAGS_UNLIT_BIT},
5 pbr_deferred_types as deferred_types,
6 pbr_functions,
7 rgb9e5,
8 mesh_view_bindings::view,
9 utils::{octahedral_encode, octahedral_decode},
10 prepass_io::FragmentOutput,
11 view_transformations::{position_ndc_to_world, frag_coord_to_ndc},
14#ifdef MESHLET_MESH_MATERIAL_PASS
15#import bevy_pbr::meshlet_visibility_buffer_resolve::VertexOutput
16#else
17#import bevy_pbr::prepass_io::VertexOutput
18#endif
20#ifdef MOTION_VECTOR_PREPASS
21 #import bevy_pbr::pbr_prepass_functions::calculate_motion_vector
22#endif
24// Creates the deferred gbuffer from a PbrInput.
25fn deferred_gbuffer_from_pbr_input(in: PbrInput) -> vec4<u32> {
26 // Only monochrome occlusion supported. May not be worth including at all.
27 // Some models have baked occlusion, GLTF only supports monochrome.
28 // Real time occlusion is applied in the deferred lighting pass.
29 // Deriving luminance via Rec. 709. coefficients
30 // https://en.wikipedia.org/wiki/Rec._709
31 let diffuse_occlusion = dot(in.diffuse_occlusion, vec3<f32>(0.2126, 0.7152, 0.0722));
32#ifdef WEBGL2 // More crunched for webgl so we can also fit depth.
33 var props = deferred_types::pack_unorm3x4_plus_unorm_20_(vec4(
34 in.material.reflectance,
35 in.material.metallic,
36 diffuse_occlusion,
37 in.frag_coord.z));
38#else
39 var props = deferred_types::pack_unorm4x8_(vec4(
40 in.material.reflectance, // could be fewer bits
41 in.material.metallic, // could be fewer bits
42 diffuse_occlusion, // is this worth including?
43 0.0)); // spare
44#endif // WEBGL2
45 let flags = deferred_types::deferred_flags_from_mesh_material_flags(in.flags, in.material.flags);
46 let octahedral_normal = octahedral_encode(normalize(in.N));
47 var base_color_srgb = vec3(0.0);
48 var emissive = in.material.emissive.rgb;
49 if ((in.material.flags & STANDARD_MATERIAL_FLAGS_UNLIT_BIT) != 0u) {
50 // Material is unlit, use emissive component of gbuffer for color data.
51 // Unlit materials are effectively emissive.
52 emissive = in.material.base_color.rgb;
53 } else {
54 base_color_srgb = pow(in.material.base_color.rgb, vec3(1.0 / 2.2));
55 }
57 // Utilize the emissive channel to transmit the lightmap data. To ensure
58 // it matches the output in forward shading, pre-multiply it with the
59 // calculated diffuse color.
60 let base_color = in.material.base_color.rgb;
61 let metallic = in.material.metallic;
62 let specular_transmission = in.material.specular_transmission;
63 let diffuse_transmission = in.material.diffuse_transmission;
64 let diffuse_color = pbr_functions::calculate_diffuse_color(
65 base_color,
66 metallic,
67 specular_transmission,
68 diffuse_transmission
69 );
70 emissive += in.lightmap_light * diffuse_color * view.exposure;
72 let deferred = vec4(
73 deferred_types::pack_unorm4x8_(vec4(base_color_srgb, in.material.perceptual_roughness)),
74 rgb9e5::vec3_to_rgb9e5_(emissive),
75 props,
76 deferred_types::pack_24bit_normal_and_flags(octahedral_normal, flags),
77 );
78 return deferred;
81// Creates a PbrInput from the deferred gbuffer.
82fn pbr_input_from_deferred_gbuffer(frag_coord: vec4<f32>, gbuffer: vec4<u32>) -> PbrInput {
83 var pbr = pbr_input_new();
85 let flags = deferred_types::unpack_flags(gbuffer.a);
86 let deferred_flags = deferred_types::mesh_material_flags_from_deferred_flags(flags);
87 pbr.flags = deferred_flags.x;
88 pbr.material.flags = deferred_flags.y;
90 let base_rough = deferred_types::unpack_unorm4x8_(gbuffer.r);
91 pbr.material.perceptual_roughness = base_rough.a;
92 let emissive = rgb9e5::rgb9e5_to_vec3_(gbuffer.g);
93 if ((pbr.material.flags & STANDARD_MATERIAL_FLAGS_UNLIT_BIT) != 0u) {
94 pbr.material.base_color = vec4(emissive, 1.0);
95 pbr.material.emissive = vec4(vec3(0.0), 0.0);
96 } else {
97 pbr.material.base_color = vec4(pow(base_rough.rgb, vec3(2.2)), 1.0);
98 pbr.material.emissive = vec4(emissive, 0.0);
99 }
100#ifdef WEBGL2 // More crunched for webgl so we can also fit depth.
101 let props = deferred_types::unpack_unorm3x4_plus_unorm_20_(gbuffer.b);
102 // Bias to 0.5 since that's the value for almost all materials.
103 pbr.material.reflectance = saturate(props.r - 0.03333333333);
104#else
105 let props = deferred_types::unpack_unorm4x8_(gbuffer.b);
106 pbr.material.reflectance = props.r;
107#endif // WEBGL2
108 pbr.material.metallic = props.g;
109 pbr.diffuse_occlusion = vec3(props.b);
110 let octahedral_normal = deferred_types::unpack_24bit_normal(gbuffer.a);
111 let N = octahedral_decode(octahedral_normal);
113 let world_position = vec4(position_ndc_to_world(frag_coord_to_ndc(frag_coord)), 1.0);
114 let is_orthographic = view.clip_from_view[3].w == 1.0;
115 let V = pbr_functions::calculate_view(world_position, is_orthographic);
117 pbr.frag_coord = frag_coord;
118 pbr.world_normal = N;
119 pbr.world_position = world_position;
120 pbr.N = N;
121 pbr.V = V;
122 pbr.is_orthographic = is_orthographic;
124 return pbr;
127#ifdef PREPASS_PIPELINE
128fn deferred_output(in: VertexOutput, pbr_input: PbrInput) -> FragmentOutput {
129 var out: FragmentOutput;
131 // gbuffer
132 out.deferred = deferred_gbuffer_from_pbr_input(pbr_input);
133 // lighting pass id (used to determine which lighting shader to run for the fragment)
134 out.deferred_lighting_pass_id = pbr_input.material.deferred_lighting_pass_id;
135 // normal if required
136#ifdef NORMAL_PREPASS
137 out.normal = vec4(in.world_normal * 0.5 + vec3(0.5), 1.0);
138#endif
139 // motion vectors if required
140#ifdef MOTION_VECTOR_PREPASS
141#ifdef MESHLET_MESH_MATERIAL_PASS
142 out.motion_vector = in.motion_vector;
143#else
144 out.motion_vector = calculate_motion_vector(in.world_position, in.previous_world_position);
145#endif
146#endif
148 return out;
150#endif
Contents