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_fragment
3#import bevy_pbr::{
4 pbr_functions,
5 pbr_functions::SampleBias,
6 pbr_bindings,
7 pbr_types,
8 prepass_utils,
9 lighting,
10 mesh_bindings::mesh,
11 mesh_view_bindings::view,
12 parallax_mapping::parallaxed_uv,
13 lightmap::lightmap,
16#ifdef SCREEN_SPACE_AMBIENT_OCCLUSION
17#import bevy_pbr::mesh_view_bindings::screen_space_ambient_occlusion_texture
18#import bevy_pbr::ssao_utils::ssao_multibounce
19#endif
21#ifdef MESHLET_MESH_MATERIAL_PASS
22#import bevy_pbr::meshlet_visibility_buffer_resolve::VertexOutput
23#else ifdef PREPASS_PIPELINE
24#import bevy_pbr::prepass_io::VertexOutput
25#else
26#import bevy_pbr::forward_io::VertexOutput
27#endif
29// prepare a basic PbrInput from the vertex stage output, mesh binding and view binding
30fn pbr_input_from_vertex_output(
31 in: VertexOutput,
32 is_front: bool,
33 double_sided: bool,
34) -> pbr_types::PbrInput {
35 var pbr_input: pbr_types::PbrInput = pbr_types::pbr_input_new();
37#ifdef MESHLET_MESH_MATERIAL_PASS
38 pbr_input.flags = in.mesh_flags;
39#else
40 pbr_input.flags = mesh[in.instance_index].flags;
41#endif
43 pbr_input.is_orthographic = view.clip_from_view[3].w == 1.0;
44 pbr_input.V = pbr_functions::calculate_view(in.world_position, pbr_input.is_orthographic);
45 pbr_input.frag_coord = in.position;
46 pbr_input.world_position = in.world_position;
48#ifdef VERTEX_COLORS
49 pbr_input.material.base_color = in.color;
50#endif
52 pbr_input.world_normal = pbr_functions::prepare_world_normal(
53 in.world_normal,
54 double_sided,
55 is_front,
56 );
58#ifdef LOAD_PREPASS_NORMALS
59 pbr_input.N = prepass_utils::prepass_normal(in.position, 0u);
60#else
61 pbr_input.N = normalize(pbr_input.world_normal);
62#endif
64 return pbr_input;
67// Prepare a full PbrInput by sampling all textures to resolve
68// the material members
69fn pbr_input_from_standard_material(
70 in: VertexOutput,
71 is_front: bool,
72) -> pbr_types::PbrInput {
73 let double_sided = (pbr_bindings::material.flags & pbr_types::STANDARD_MATERIAL_FLAGS_DOUBLE_SIDED_BIT) != 0u;
75 var pbr_input: pbr_types::PbrInput = pbr_input_from_vertex_output(in, is_front, double_sided);
76 pbr_input.material.flags = pbr_bindings::material.flags;
77 pbr_input.material.base_color *= pbr_bindings::material.base_color;
78 pbr_input.material.deferred_lighting_pass_id = pbr_bindings::material.deferred_lighting_pass_id;
80 // Neubelt and Pettineo 2013, "Crafting a Next-gen Material Pipeline for The Order: 1886"
81 let NdotV = max(dot(pbr_input.N, pbr_input.V), 0.0001);
83 // Fill in the sample bias so we can sample from textures.
84 var bias: SampleBias;
85#ifdef MESHLET_MESH_MATERIAL_PASS
86 bias.ddx_uv = in.ddx_uv;
87 bias.ddy_uv = in.ddy_uv;
88#else // MESHLET_MESH_MATERIAL_PASS
89 bias.mip_bias = view.mip_bias;
90#endif // MESHLET_MESH_MATERIAL_PASS
92// TODO: Transforming UVs mean we need to apply derivative chain rule for meshlet mesh material pass
93#ifdef VERTEX_UVS
94 let uv_transform = pbr_bindings::material.uv_transform;
95#ifdef VERTEX_UVS_A
96 var uv = (uv_transform * vec3(in.uv, 1.0)).xy;
97#endif
99// TODO: Transforming UVs mean we need to apply derivative chain rule for meshlet mesh material pass
100#ifdef VERTEX_UVS_B
101 var uv_b = (uv_transform * vec3(in.uv_b, 1.0)).xy;
102#else
103 var uv_b = uv;
104#endif
106#ifdef VERTEX_TANGENTS
107 if ((pbr_bindings::material.flags & pbr_types::STANDARD_MATERIAL_FLAGS_DEPTH_MAP_BIT) != 0u) {
108 let V = pbr_input.V;
109 let TBN = pbr_functions::calculate_tbn_mikktspace(in.world_normal, in.world_tangent);
110 let T = TBN[0];
111 let B = TBN[1];
112 let N = TBN[2];
113 // Transform V from fragment to camera in world space to tangent space.
114 let Vt = vec3(dot(V, T), dot(V, B), dot(V, N));
115#ifdef VERTEX_UVS_A
116 // TODO: Transforming UVs mean we need to apply derivative chain rule for meshlet mesh material pass
117 uv = parallaxed_uv(
118 pbr_bindings::material.parallax_depth_scale,
119 pbr_bindings::material.max_parallax_layer_count,
120 pbr_bindings::material.max_relief_mapping_search_steps,
121 uv,
122 // Flip the direction of Vt to go toward the surface to make the
123 // parallax mapping algorithm easier to understand and reason
124 // about.
125 -Vt,
126 );
127#endif
129#ifdef VERTEX_UVS_B
130 // TODO: Transforming UVs mean we need to apply derivative chain rule for meshlet mesh material pass
131 uv_b = parallaxed_uv(
132 pbr_bindings::material.parallax_depth_scale,
133 pbr_bindings::material.max_parallax_layer_count,
134 pbr_bindings::material.max_relief_mapping_search_steps,
135 uv_b,
136 // Flip the direction of Vt to go toward the surface to make the
137 // parallax mapping algorithm easier to understand and reason
138 // about.
139 -Vt,
140 );
141#else
142 uv_b = uv;
143#endif
144 }
145#endif // VERTEX_TANGENTS
147 if ((pbr_bindings::material.flags & pbr_types::STANDARD_MATERIAL_FLAGS_BASE_COLOR_TEXTURE_BIT) != 0u) {
148 pbr_input.material.base_color *= pbr_functions::sample_texture(
149 pbr_bindings::base_color_texture,
150 pbr_bindings::base_color_sampler,
151#ifdef STANDARD_MATERIAL_BASE_COLOR_UV_B
152 uv_b,
153#else
154 uv,
155#endif
156 bias,
157 );
159#ifdef ALPHA_TO_COVERAGE
160 // Sharpen alpha edges.
161 //
162 // https://bgolus.medium.com/anti-aliased-alpha-test-the-esoteric-alpha-to-coverage-8b177335ae4f
163 let alpha_mode = pbr_bindings::material.flags &
164 pbr_types::STANDARD_MATERIAL_FLAGS_ALPHA_MODE_RESERVED_BITS;
165 if alpha_mode == pbr_types::STANDARD_MATERIAL_FLAGS_ALPHA_MODE_ALPHA_TO_COVERAGE {
166 pbr_input.material.base_color.a = (pbr_input.material.base_color.a -
167 pbr_bindings::material.alpha_cutoff) /
168 max(fwidth(pbr_input.material.base_color.a), 0.0001) + 0.5;
169 }
170#endif // ALPHA_TO_COVERAGE
172 }
173#endif // VERTEX_UVS
175 pbr_input.material.flags = pbr_bindings::material.flags;
177 // NOTE: Unlit bit not set means == 0 is true, so the true case is if lit
178 if ((pbr_bindings::material.flags & pbr_types::STANDARD_MATERIAL_FLAGS_UNLIT_BIT) == 0u) {
179 pbr_input.material.reflectance = pbr_bindings::material.reflectance;
180 pbr_input.material.ior = pbr_bindings::material.ior;
181 pbr_input.material.attenuation_color = pbr_bindings::material.attenuation_color;
182 pbr_input.material.attenuation_distance = pbr_bindings::material.attenuation_distance;
183 pbr_input.material.alpha_cutoff = pbr_bindings::material.alpha_cutoff;
185 // emissive
186 var emissive: vec4<f32> = pbr_bindings::material.emissive;
187#ifdef VERTEX_UVS
188 if ((pbr_bindings::material.flags & pbr_types::STANDARD_MATERIAL_FLAGS_EMISSIVE_TEXTURE_BIT) != 0u) {
189 emissive = vec4<f32>(emissive.rgb * pbr_functions::sample_texture(
190 pbr_bindings::emissive_texture,
191 pbr_bindings::emissive_sampler,
192#ifdef STANDARD_MATERIAL_EMISSIVE_UV_B
193 uv_b,
194#else
195 uv,
196#endif
197 bias,
198 ).rgb, emissive.a);
199 }
200#endif
201 pbr_input.material.emissive = emissive;
203 // metallic and perceptual roughness
204 var metallic: f32 = pbr_bindings::material.metallic;
205 var perceptual_roughness: f32 = pbr_bindings::material.perceptual_roughness;
206 let roughness = lighting::perceptualRoughnessToRoughness(perceptual_roughness);
207#ifdef VERTEX_UVS
208 if ((pbr_bindings::material.flags & pbr_types::STANDARD_MATERIAL_FLAGS_METALLIC_ROUGHNESS_TEXTURE_BIT) != 0u) {
209 let metallic_roughness = pbr_functions::sample_texture(
210 pbr_bindings::metallic_roughness_texture,
211 pbr_bindings::metallic_roughness_sampler,
212#ifdef STANDARD_MATERIAL_METALLIC_ROUGHNESS_UV_B
213 uv_b,
214#else
215 uv,
216#endif
217 bias,
218 );
219 // Sampling from GLTF standard channels for now
220 metallic *= metallic_roughness.b;
221 perceptual_roughness *= metallic_roughness.g;
222 }
223#endif
224 pbr_input.material.metallic = metallic;
225 pbr_input.material.perceptual_roughness = perceptual_roughness;
227 // Clearcoat factor
228 pbr_input.material.clearcoat = pbr_bindings::material.clearcoat;
229#ifdef VERTEX_UVS
230#ifdef PBR_MULTI_LAYER_MATERIAL_TEXTURES_SUPPORTED
231 if ((pbr_bindings::material.flags & pbr_types::STANDARD_MATERIAL_FLAGS_CLEARCOAT_TEXTURE_BIT) != 0u) {
232 pbr_input.material.clearcoat *= pbr_functions::sample_texture(
233 pbr_bindings::clearcoat_texture,
234 pbr_bindings::clearcoat_sampler,
235#ifdef STANDARD_MATERIAL_CLEARCOAT_UV_B
236 uv_b,
237#else
238 uv,
239#endif
240 bias,
241 ).r;
242 }
243#endif // PBR_MULTI_LAYER_MATERIAL_TEXTURES_SUPPORTED
244#endif // VERTEX_UVS
246 // Clearcoat roughness
247 pbr_input.material.clearcoat_perceptual_roughness = pbr_bindings::material.clearcoat_perceptual_roughness;
248#ifdef VERTEX_UVS
249#ifdef PBR_MULTI_LAYER_MATERIAL_TEXTURES_SUPPORTED
250 if ((pbr_bindings::material.flags & pbr_types::STANDARD_MATERIAL_FLAGS_CLEARCOAT_ROUGHNESS_TEXTURE_BIT) != 0u) {
251 pbr_input.material.clearcoat_perceptual_roughness *= pbr_functions::sample_texture(
252 pbr_bindings::clearcoat_roughness_texture,
253 pbr_bindings::clearcoat_roughness_sampler,
254#ifdef STANDARD_MATERIAL_CLEARCOAT_ROUGHNESS_UV_B
255 uv_b,
256#else
257 uv,
258#endif
259 bias,
260 ).g;
261 }
262#endif // PBR_MULTI_LAYER_MATERIAL_TEXTURES_SUPPORTED
263#endif // VERTEX_UVS
265 var specular_transmission: f32 = pbr_bindings::material.specular_transmission;
266#ifdef VERTEX_UVS
267#ifdef PBR_TRANSMISSION_TEXTURES_SUPPORTED
268 if ((pbr_bindings::material.flags & pbr_types::STANDARD_MATERIAL_FLAGS_SPECULAR_TRANSMISSION_TEXTURE_BIT) != 0u) {
269 specular_transmission *= pbr_functions::sample_texture(
270 pbr_bindings::specular_transmission_texture,
271 pbr_bindings::specular_transmission_sampler,
272#ifdef STANDARD_MATERIAL_SPECULAR_TRANSMISSION_UV_B
273 uv_b,
274#else
275 uv,
276#endif
277 bias,
278 ).r;
279 }
280#endif
281#endif
282 pbr_input.material.specular_transmission = specular_transmission;
284 var thickness: f32 = pbr_bindings::material.thickness;
285#ifdef VERTEX_UVS
286#ifdef PBR_TRANSMISSION_TEXTURES_SUPPORTED
287 if ((pbr_bindings::material.flags & pbr_types::STANDARD_MATERIAL_FLAGS_THICKNESS_TEXTURE_BIT) != 0u) {
288 thickness *= pbr_functions::sample_texture(
289 pbr_bindings::thickness_texture,
290 pbr_bindings::thickness_sampler,
291#ifdef STANDARD_MATERIAL_THICKNESS_UV_B
292 uv_b,
293#else
294 uv,
295#endif
296 bias,
297 ).g;
298 }
299#endif
300#endif
301 // scale thickness, accounting for non-uniform scaling (e.g. a “squished” mesh)
302 // TODO: Meshlet support
303#ifndef MESHLET_MESH_MATERIAL_PASS
304 thickness *= length(
305 (transpose(mesh[in.instance_index].world_from_local) * vec4(pbr_input.N, 0.0)).xyz
306 );
307#endif
308 pbr_input.material.thickness = thickness;
310 var diffuse_transmission = pbr_bindings::material.diffuse_transmission;
311#ifdef VERTEX_UVS
312#ifdef PBR_TRANSMISSION_TEXTURES_SUPPORTED
313 if ((pbr_bindings::material.flags & pbr_types::STANDARD_MATERIAL_FLAGS_DIFFUSE_TRANSMISSION_TEXTURE_BIT) != 0u) {
314 diffuse_transmission *= pbr_functions::sample_texture(
315 pbr_bindings::diffuse_transmission_texture,
316 pbr_bindings::diffuse_transmission_sampler,
317#ifdef STANDARD_MATERIAL_DIFFUSE_TRANSMISSION_UV_B
318 uv_b,
319#else
320 uv,
321#endif
322 bias,
323 ).a;
324 }
325#endif
326#endif
327 pbr_input.material.diffuse_transmission = diffuse_transmission;
329 var diffuse_occlusion: vec3<f32> = vec3(1.0);
330 var specular_occlusion: f32 = 1.0;
331#ifdef VERTEX_UVS
332 if ((pbr_bindings::material.flags & pbr_types::STANDARD_MATERIAL_FLAGS_OCCLUSION_TEXTURE_BIT) != 0u) {
333 diffuse_occlusion *= pbr_functions::sample_texture(
334 pbr_bindings::occlusion_texture,
335 pbr_bindings::occlusion_sampler,
336#ifdef STANDARD_MATERIAL_OCCLUSION_UV_B
337 uv_b,
338#else
339 uv,
340#endif
341 bias,
342 ).r;
343 }
344#endif
345#ifdef SCREEN_SPACE_AMBIENT_OCCLUSION
346 let ssao = textureLoad(screen_space_ambient_occlusion_texture, vec2<i32>(in.position.xy), 0i).r;
347 let ssao_multibounce = ssao_multibounce(ssao, pbr_input.material.base_color.rgb);
348 diffuse_occlusion = min(diffuse_occlusion, ssao_multibounce);
349 // Use SSAO to estimate the specular occlusion.
350 // Lagarde and Rousiers 2014, "Moving Frostbite to Physically Based Rendering"
351 specular_occlusion = saturate(pow(NdotV + ssao, exp2(-16.0 * roughness - 1.0)) - 1.0 + ssao);
352#endif
353 pbr_input.diffuse_occlusion = diffuse_occlusion;
354 pbr_input.specular_occlusion = specular_occlusion;
356 // N (normal vector)
357#ifndef LOAD_PREPASS_NORMALS
359 pbr_input.N = normalize(pbr_input.world_normal);
360 pbr_input.clearcoat_N = pbr_input.N;
362#ifdef VERTEX_UVS
363#ifdef VERTEX_TANGENTS
365 let TBN = pbr_functions::calculate_tbn_mikktspace(pbr_input.world_normal, in.world_tangent);
367#ifdef STANDARD_MATERIAL_NORMAL_MAP
369 let Nt = pbr_functions::sample_texture(
370 pbr_bindings::normal_map_texture,
371 pbr_bindings::normal_map_sampler,
372#ifdef STANDARD_MATERIAL_NORMAL_MAP_UV_B
373 uv_b,
374#else
375 uv,
376#endif
377 bias,
378 ).rgb;
380 pbr_input.N = pbr_functions::apply_normal_mapping(
381 pbr_bindings::material.flags,
382 TBN,
383 double_sided,
384 is_front,
385 Nt,
386 );
388#endif // STANDARD_MATERIAL_NORMAL_MAP
390#ifdef STANDARD_MATERIAL_CLEARCOAT
392 // Note: `KHR_materials_clearcoat` specifies that, if there's no
393 // clearcoat normal map, we must set the normal to the mesh's normal,
394 // and not to the main layer's bumped normal.
396#ifdef STANDARD_MATERIAL_CLEARCOAT_NORMAL_MAP
398 let clearcoat_Nt = pbr_functions::sample_texture(
399 pbr_bindings::clearcoat_normal_texture,
400 pbr_bindings::clearcoat_normal_sampler,
401#ifdef STANDARD_MATERIAL_CLEARCOAT_NORMAL_UV_B
402 uv_b,
403#else
404 uv,
405#endif
406 bias,
407 ).rgb;
409 pbr_input.clearcoat_N = pbr_functions::apply_normal_mapping(
410 pbr_bindings::material.flags,
411 TBN,
412 double_sided,
413 is_front,
414 clearcoat_Nt,
415 );
417#endif // STANDARD_MATERIAL_CLEARCOAT_NORMAL_MAP
419#endif // STANDARD_MATERIAL_CLEARCOAT
421#endif // VERTEX_TANGENTS
422#endif // VERTEX_UVS
424 // Take anisotropy into account.
425 //
426 // This code comes from the `KHR_materials_anisotropy` spec:
427 // <https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_materials_anisotropy/README.md#individual-lights>
428#ifdef PBR_ANISOTROPY_TEXTURE_SUPPORTED
429#ifdef VERTEX_TANGENTS
430#ifdef STANDARD_MATERIAL_ANISOTROPY
432 var anisotropy_strength = pbr_bindings::material.anisotropy_strength;
433 var anisotropy_direction = pbr_bindings::material.anisotropy_rotation;
435 // Adjust based on the anisotropy map if there is one.
436 if ((pbr_bindings::material.flags & pbr_types::STANDARD_MATERIAL_FLAGS_ANISOTROPY_TEXTURE_BIT) != 0u) {
437 let anisotropy_texel = pbr_functions::sample_texture(
438 pbr_bindings::anisotropy_texture,
439 pbr_bindings::anisotropy_sampler,
440#ifdef STANDARD_MATERIAL_ANISOTROPY_UV_B
441 uv_b,
442#else // STANDARD_MATERIAL_ANISOTROPY_UV_B
443 uv,
444#endif // STANDARD_MATERIAL_ANISOTROPY_UV_B
445 bias,
446 ).rgb;
448 let anisotropy_direction_from_texture = normalize(anisotropy_texel.rg * 2.0 - 1.0);
449 // Rotate by the anisotropy direction.
450 anisotropy_direction =
451 mat2x2(anisotropy_direction.xy, anisotropy_direction.yx * vec2(-1.0, 1.0)) *
452 anisotropy_direction_from_texture;
453 anisotropy_strength *= anisotropy_texel.b;
454 }
456 pbr_input.anisotropy_strength = anisotropy_strength;
458 let anisotropy_T = normalize(TBN * vec3(anisotropy_direction, 0.0));
459 let anisotropy_B = normalize(cross(pbr_input.world_normal, anisotropy_T));
460 pbr_input.anisotropy_T = anisotropy_T;
461 pbr_input.anisotropy_B = anisotropy_B;
463#endif // STANDARD_MATERIAL_ANISOTROPY
464#endif // VERTEX_TANGENTS
465#endif // PBR_ANISOTROPY_TEXTURE_SUPPORTED
467#endif // LOAD_PREPASS_NORMALS
469// TODO: Meshlet support
470#ifdef LIGHTMAP
471 pbr_input.lightmap_light = lightmap(
472 in.uv_b,
473 pbr_bindings::material.lightmap_exposure,
474 in.instance_index);
475#endif
476 }
478 return pbr_input;
Contents