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 rec_709_coeffs = vec3<f32>(0.2126, 0.7152, 0.0722);
32 let diffuse_occlusion = dot(in.diffuse_occlusion, rec_709_coeffs);
33 // Only monochrome specular supported.
34 let reflectance = dot(in.material.reflectance, rec_709_coeffs);
35#ifdef WEBGL2 // More crunched for webgl so we can also fit depth.
36 var props = deferred_types::pack_unorm3x4_plus_unorm_20_(vec4(
37 reflectance,
38 in.material.metallic,
39 diffuse_occlusion,
40 in.frag_coord.z));
41#else
42 let clearcoat = u32(round(saturate(in.material.clearcoat) * 15.0));
43 let clearcoat_perceptual_roughness =
44 u32(round(clamp(in.material.clearcoat_perceptual_roughness, 0.0, 0.5) * 30.0));
45 let clearcoat_props = f32(clearcoat | (clearcoat_perceptual_roughness << 4u)) / 255.0;
46 var props = deferred_types::pack_unorm4x8_(vec4(
47 reflectance, // could be fewer bits
48 in.material.metallic, // could be fewer bits
49 diffuse_occlusion, // is this worth including?
50 clearcoat_props));
51#endif // WEBGL2
52 let flags = deferred_types::deferred_flags_from_mesh_material_flags(in.flags, in.material.flags);
53 let octahedral_normal = octahedral_encode(normalize(in.N));
54 var base_color_srgb = vec3(0.0);
55 var emissive = in.material.emissive.rgb;
56 if ((in.material.flags & STANDARD_MATERIAL_FLAGS_UNLIT_BIT) != 0u) {
57 // Material is unlit, use emissive component of gbuffer for color data.
58 // Unlit materials are effectively emissive.
59 emissive = in.material.base_color.rgb;
60 } else {
61 base_color_srgb = pow(in.material.base_color.rgb, vec3(1.0 / 2.2));
62 }
64 // Utilize the emissive channel to transmit the lightmap data. To ensure
65 // it matches the output in forward shading, pre-multiply it with the
66 // calculated diffuse color.
67 let base_color = in.material.base_color.rgb;
68 let metallic = in.material.metallic;
69 let specular_transmission = in.material.specular_transmission;
70 let diffuse_transmission = in.material.diffuse_transmission;
71 let diffuse_color = pbr_functions::calculate_diffuse_color(
72 base_color,
73 metallic,
74 specular_transmission,
75 diffuse_transmission
76 );
77 emissive += in.lightmap_light * diffuse_color * view.exposure;
79 let deferred = vec4(
80 deferred_types::pack_unorm4x8_(vec4(base_color_srgb, in.material.perceptual_roughness)),
81 rgb9e5::vec3_to_rgb9e5_(emissive),
82 props,
83 deferred_types::pack_24bit_normal_and_flags(octahedral_normal, flags),
84 );
85 return deferred;
88// Creates a PbrInput from the deferred gbuffer.
89fn pbr_input_from_deferred_gbuffer(frag_coord: vec4<f32>, gbuffer: vec4<u32>) -> PbrInput {
90 var pbr = pbr_input_new();
92 let flags = deferred_types::unpack_flags(gbuffer.a);
93 let deferred_flags = deferred_types::mesh_material_flags_from_deferred_flags(flags);
94 pbr.flags = deferred_flags.x;
95 pbr.material.flags = deferred_flags.y;
97 let base_rough = deferred_types::unpack_unorm4x8_(gbuffer.r);
98 pbr.material.perceptual_roughness = base_rough.a;
99 let emissive = rgb9e5::rgb9e5_to_vec3_(gbuffer.g);
100 if ((pbr.material.flags & STANDARD_MATERIAL_FLAGS_UNLIT_BIT) != 0u) {
101 pbr.material.base_color = vec4(emissive, 1.0);
102 pbr.material.emissive = vec4(vec3(0.0), 0.0);
103 } else {
104 pbr.material.base_color = vec4(pow(base_rough.rgb, vec3(2.2)), 1.0);
105 pbr.material.emissive = vec4(emissive, 0.0);
106 }
107#ifdef WEBGL2 // More crunched for webgl so we can also fit depth.
108 let props = deferred_types::unpack_unorm3x4_plus_unorm_20_(gbuffer.b);
109 // Bias to 0.5 since that's the value for almost all materials.
110 pbr.material.reflectance = vec3(saturate(props.r - 0.03333333333));
111#else
112 let props = deferred_types::unpack_unorm4x8_(gbuffer.b);
113 let clearcoat_props = u32(round(props.a * 255.0));
114 pbr.material.reflectance = vec3(props.r);
115 pbr.material.clearcoat = f32(clearcoat_props & 0x0fu) / 15.0;
116 pbr.material.clearcoat_perceptual_roughness = f32(clearcoat_props >> 4u) / 30.0;
117#endif // WEBGL2
118 pbr.material.metallic = props.g;
119 pbr.diffuse_occlusion = vec3(props.b);
120 let octahedral_normal = deferred_types::unpack_24bit_normal(gbuffer.a);
121 let N = octahedral_decode(octahedral_normal);
123 let world_position = vec4(position_ndc_to_world(frag_coord_to_ndc(frag_coord)), 1.0);
124 let is_orthographic = view.clip_from_view[3].w == 1.0;
125 let V = pbr_functions::calculate_view(world_position, is_orthographic);
127 pbr.frag_coord = frag_coord;
128 pbr.world_normal = N;
129 pbr.world_position = world_position;
130 pbr.N = N;
131 pbr.V = V;
132 pbr.clearcoat_N = N;
133 pbr.is_orthographic = is_orthographic;
135 return pbr;
138#ifdef PREPASS_PIPELINE
139fn deferred_output(in: VertexOutput, pbr_input: PbrInput) -> FragmentOutput {
140 var out: FragmentOutput;
142 // gbuffer
143 out.deferred = deferred_gbuffer_from_pbr_input(pbr_input);
144 // lighting pass id (used to determine which lighting shader to run for the fragment)
145 out.deferred_lighting_pass_id = pbr_input.material.deferred_lighting_pass_id;
146 // normal if required
147#ifdef NORMAL_PREPASS
148 out.normal = vec4(in.world_normal * 0.5 + vec3(0.5), 1.0);
149#endif
150 // motion vectors if required
151#ifdef MOTION_VECTOR_PREPASS
152#ifdef MESHLET_MESH_MATERIAL_PASS
153 out.motion_vector = in.motion_vector;
154#else
155 out.motion_vector = calculate_motion_vector(in.world_position, in.previous_world_position);
156#endif
157#endif
159 return out;
161#endif
Contents