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_render::bindless::{bindless_samplers_filtering, bindless_textures_2d}
5#import bevy_pbr::{
6 pbr_functions,
7 pbr_functions::SampleBias,
8 pbr_bindings,
9 pbr_types,
10 prepass_utils,
11 lighting,
12 mesh_bindings::mesh,
13 mesh_view_bindings::view,
14 parallax_mapping::parallaxed_uv,
15 lightmap::lightmap,
18#ifdef SCREEN_SPACE_AMBIENT_OCCLUSION
19#import bevy_pbr::mesh_view_bindings::screen_space_ambient_occlusion_texture
20#import bevy_pbr::ssao_utils::ssao_multibounce
21#endif
23#ifdef MESHLET_MESH_MATERIAL_PASS
24#import bevy_pbr::meshlet_visibility_buffer_resolve::VertexOutput
25#else ifdef PREPASS_PIPELINE
26#import bevy_pbr::prepass_io::VertexOutput
27#else
28#import bevy_pbr::forward_io::VertexOutput
29#endif
31#ifdef BINDLESS
32#import bevy_pbr::pbr_bindings::material_indices
33#endif // BINDLESS
35// prepare a basic PbrInput from the vertex stage output, mesh binding and view binding
36fn pbr_input_from_vertex_output(
37 in: VertexOutput,
38 is_front: bool,
39 double_sided: bool,
40) -> pbr_types::PbrInput {
41 var pbr_input: pbr_types::PbrInput = pbr_types::pbr_input_new();
43#ifdef MESHLET_MESH_MATERIAL_PASS
44 pbr_input.flags = in.mesh_flags;
45#else
46 pbr_input.flags = mesh[in.instance_index].flags;
47#endif
49 pbr_input.is_orthographic = view.clip_from_view[3].w == 1.0;
50 pbr_input.V = pbr_functions::calculate_view(in.world_position, pbr_input.is_orthographic);
51 pbr_input.frag_coord = in.position;
52 pbr_input.world_position = in.world_position;
54#ifdef VERTEX_COLORS
55 pbr_input.material.base_color = in.color;
56#endif
58 pbr_input.world_normal = pbr_functions::prepare_world_normal(
59 in.world_normal,
60 double_sided,
61 is_front,
62 );
64#ifdef LOAD_PREPASS_NORMALS
65 pbr_input.N = prepass_utils::prepass_normal(in.position, 0u);
66#else
67 pbr_input.N = normalize(pbr_input.world_normal);
68#endif
70 return pbr_input;
73// Prepare a full PbrInput by sampling all textures to resolve
74// the material members
75fn pbr_input_from_standard_material(
76 in: VertexOutput,
77 is_front: bool,
78) -> pbr_types::PbrInput {
79#ifdef MESHLET_MESH_MATERIAL_PASS
80 let slot = in.material_bind_group_slot;
81#else // MESHLET_MESH_MATERIAL_PASS
82 let slot = mesh[in.instance_index].material_and_lightmap_bind_group_slot & 0xffffu;
83#endif // MESHLET_MESH_MATERIAL_PASS
84#ifdef BINDLESS
85 let flags = pbr_bindings::material_array[material_indices[slot].material].flags;
86 let base_color = pbr_bindings::material_array[material_indices[slot].material].base_color;
87 let deferred_lighting_pass_id =
88 pbr_bindings::material_array[material_indices[slot].material].deferred_lighting_pass_id;
89 let alpha_cutoff = pbr_bindings::material_array[material_indices[slot].material].alpha_cutoff;
90#else // BINDLESS
91 let flags = pbr_bindings::material.flags;
92 let base_color = pbr_bindings::material.base_color;
93 let deferred_lighting_pass_id = pbr_bindings::material.deferred_lighting_pass_id;
94 let alpha_cutoff = pbr_bindings::material.alpha_cutoff;
95#endif
97 let double_sided = (flags & pbr_types::STANDARD_MATERIAL_FLAGS_DOUBLE_SIDED_BIT) != 0u;
99 var pbr_input: pbr_types::PbrInput = pbr_input_from_vertex_output(in, is_front, double_sided);
100 pbr_input.material.flags = flags;
101 pbr_input.material.base_color *= base_color;
102 pbr_input.material.deferred_lighting_pass_id = deferred_lighting_pass_id;
104 // Neubelt and Pettineo 2013, "Crafting a Next-gen Material Pipeline for The Order: 1886"
105 let NdotV = max(dot(pbr_input.N, pbr_input.V), 0.0001);
107 // Fill in the sample bias so we can sample from textures.
108 var bias: SampleBias;
109#ifdef MESHLET_MESH_MATERIAL_PASS
110 bias.ddx_uv = in.ddx_uv;
111 bias.ddy_uv = in.ddy_uv;
112#else // MESHLET_MESH_MATERIAL_PASS
113 bias.mip_bias = view.mip_bias;
114#endif // MESHLET_MESH_MATERIAL_PASS
116// TODO: Transforming UVs mean we need to apply derivative chain rule for meshlet mesh material pass
117#ifdef VERTEX_UVS
119#ifdef BINDLESS
120 let uv_transform = pbr_bindings::material_array[material_indices[slot].material].uv_transform;
121#else // BINDLESS
122 let uv_transform = pbr_bindings::material.uv_transform;
123#endif // BINDLESS
125pbr_input.material.uv_transform = uv_transform;
127#ifdef VERTEX_UVS_A
128 var uv = (uv_transform * vec3(in.uv, 1.0)).xy;
129#endif
131// TODO: Transforming UVs mean we need to apply derivative chain rule for meshlet mesh material pass
132#ifdef VERTEX_UVS_B
133 var uv_b = (uv_transform * vec3(in.uv_b, 1.0)).xy;
134#else
135 var uv_b = uv;
136#endif
138#ifdef VERTEX_TANGENTS
139 if ((flags & pbr_types::STANDARD_MATERIAL_FLAGS_DEPTH_MAP_BIT) != 0u) {
140 let V = pbr_input.V;
141 let TBN = pbr_functions::calculate_tbn_mikktspace(in.world_normal, in.world_tangent);
142 let T = TBN[0];
143 let B = TBN[1];
144 let N = TBN[2];
145 // Transform V from fragment to camera in world space to tangent space.
146 let Vt = vec3(dot(V, T), dot(V, B), dot(V, N));
147#ifdef VERTEX_UVS_A
148 // TODO: Transforming UVs mean we need to apply derivative chain rule for meshlet mesh material pass
149 uv = parallaxed_uv(
150#ifdef BINDLESS
151 pbr_bindings::material_array[material_indices[slot].material].parallax_depth_scale,
152 pbr_bindings::material_array[material_indices[slot].material].max_parallax_layer_count,
153 pbr_bindings::material_array[material_indices[slot].material].max_relief_mapping_search_steps,
154#else // BINDLESS
155 pbr_bindings::material.parallax_depth_scale,
156 pbr_bindings::material.max_parallax_layer_count,
157 pbr_bindings::material.max_relief_mapping_search_steps,
158#endif // BINDLESS
159 uv,
160 // Flip the direction of Vt to go toward the surface to make the
161 // parallax mapping algorithm easier to understand and reason
162 // about.
163 -Vt,
164 slot,
165 );
166#endif
168#ifdef VERTEX_UVS_B
169 // TODO: Transforming UVs mean we need to apply derivative chain rule for meshlet mesh material pass
170 uv_b = parallaxed_uv(
171#ifdef BINDLESS
172 pbr_bindings::material_array[material_indices[slot].material].parallax_depth_scale,
173 pbr_bindings::material_array[material_indices[slot].material].max_parallax_layer_count,
174 pbr_bindings::material_array[material_indices[slot].material].max_relief_mapping_search_steps,
175#else // BINDLESS
176 pbr_bindings::material.parallax_depth_scale,
177 pbr_bindings::material.max_parallax_layer_count,
178 pbr_bindings::material.max_relief_mapping_search_steps,
179#endif // BINDLESS
180 uv_b,
181 // Flip the direction of Vt to go toward the surface to make the
182 // parallax mapping algorithm easier to understand and reason
183 // about.
184 -Vt,
185 slot,
186 );
187#else
188 uv_b = uv;
189#endif
190 }
191#endif // VERTEX_TANGENTS
193 if ((flags & pbr_types::STANDARD_MATERIAL_FLAGS_BASE_COLOR_TEXTURE_BIT) != 0u) {
194 pbr_input.material.base_color *=
195#ifdef MESHLET_MESH_MATERIAL_PASS
196 textureSampleGrad(
197#else // MESHLET_MESH_MATERIAL_PASS
198 textureSampleBias(
199#endif // MESHLET_MESH_MATERIAL_PASS
200#ifdef BINDLESS
201 bindless_textures_2d[material_indices[slot].base_color_texture],
202 bindless_samplers_filtering[material_indices[slot].base_color_sampler],
203#else // BINDLESS
204 pbr_bindings::base_color_texture,
205 pbr_bindings::base_color_sampler,
206#endif // BINDLESS
207#ifdef STANDARD_MATERIAL_BASE_COLOR_UV_B
208 uv_b,
209#else
210 uv,
211#endif
212#ifdef MESHLET_MESH_MATERIAL_PASS
213 bias.ddx_uv,
214 bias.ddy_uv,
215#else // MESHLET_MESH_MATERIAL_PASS
216 bias.mip_bias,
217#endif // MESHLET_MESH_MATERIAL_PASS
218 );
220#ifdef ALPHA_TO_COVERAGE
221 // Sharpen alpha edges.
222 //
223 // https://bgolus.medium.com/anti-aliased-alpha-test-the-esoteric-alpha-to-coverage-8b177335ae4f
224 let alpha_mode = flags & pbr_types::STANDARD_MATERIAL_FLAGS_ALPHA_MODE_RESERVED_BITS;
225 if alpha_mode == pbr_types::STANDARD_MATERIAL_FLAGS_ALPHA_MODE_ALPHA_TO_COVERAGE {
227#ifdef BINDLESS
228 let alpha_cutoff = pbr_bindings::material_array[material_indices[slot].material].alpha_cutoff;
229#else // BINDLESS
230 let alpha_cutoff = pbr_bindings::material.alpha_cutoff;
231#endif // BINDLESS
233 pbr_input.material.base_color.a = (pbr_input.material.base_color.a - alpha_cutoff) /
234 max(fwidth(pbr_input.material.base_color.a), 0.0001) + 0.5;
235 }
236#endif // ALPHA_TO_COVERAGE
238 }
239#endif // VERTEX_UVS
241 pbr_input.material.flags = flags;
242 pbr_input.material.alpha_cutoff = alpha_cutoff;
244 // NOTE: Unlit bit not set means == 0 is true, so the true case is if lit
245 if ((flags & pbr_types::STANDARD_MATERIAL_FLAGS_UNLIT_BIT) == 0u) {
246#ifdef BINDLESS
247 pbr_input.material.ior = pbr_bindings::material_array[material_indices[slot].material].ior;
248 pbr_input.material.attenuation_color =
249 pbr_bindings::material_array[material_indices[slot].material].attenuation_color;
250 pbr_input.material.attenuation_distance =
251 pbr_bindings::material_array[material_indices[slot].material].attenuation_distance;
252#else // BINDLESS
253 pbr_input.material.ior = pbr_bindings::material.ior;
254 pbr_input.material.attenuation_color = pbr_bindings::material.attenuation_color;
255 pbr_input.material.attenuation_distance = pbr_bindings::material.attenuation_distance;
256#endif // BINDLESS
258 // reflectance
259#ifdef BINDLESS
260 pbr_input.material.reflectance =
261 pbr_bindings::material_array[material_indices[slot].material].reflectance;
262#else // BINDLESS
263 pbr_input.material.reflectance = pbr_bindings::material.reflectance;
264#endif // BINDLESS
266#ifdef PBR_SPECULAR_TEXTURES_SUPPORTED
267#ifdef VERTEX_UVS
269 // Specular texture
270 if ((flags & pbr_types::STANDARD_MATERIAL_FLAGS_SPECULAR_TEXTURE_BIT) != 0u) {
271 let specular =
272#ifdef MESHLET_MESH_MATERIAL_PASS
273 textureSampleGrad(
274#else // MESHLET_MESH_MATERIAL_PASS
275 textureSampleBias(
276#endif // MESHLET_MESH_MATERIAL_PASS
277#ifdef BINDLESS
278 bindless_textures_2d[material_indices[slot].specular_texture],
279 bindless_samplers_filtering[material_indices[slot].specular_sampler],
280#else // BINDLESS
281 pbr_bindings::specular_texture,
282 pbr_bindings::specular_sampler,
283#endif // BINDLESS
284#ifdef STANDARD_MATERIAL_SPECULAR_UV_B
285 uv_b,
286#else // STANDARD_MATERIAL_SPECULAR_UV_B
287 uv,
288#endif // STANDARD_MATERIAL_SPECULAR_UV_B
289#ifdef MESHLET_MESH_MATERIAL_PASS
290 bias.ddx_uv,
291 bias.ddy_uv,
292#else // MESHLET_MESH_MATERIAL_PASS
293 bias.mip_bias,
294#endif // MESHLET_MESH_MATERIAL_PASS
295 ).a;
296 // This 0.5 factor is from the `KHR_materials_specular` specification:
297 // <https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_materials_specular#materials-with-reflectance-parameter>
298 pbr_input.material.reflectance *= specular * 0.5;
299 }
301 // Specular tint texture
302 if ((flags & pbr_types::STANDARD_MATERIAL_FLAGS_SPECULAR_TINT_TEXTURE_BIT) != 0u) {
303 let specular_tint =
304#ifdef MESHLET_MESH_MATERIAL_PASS
305 textureSampleGrad(
306#else // MESHLET_MESH_MATERIAL_PASS
307 textureSampleBias(
308#endif // MESHLET_MESH_MATERIAL_PASS
309#ifdef BINDLESS
310 bindless_textures_2d[material_indices[slot].specular_tint_texture],
311 bindless_samplers_filtering[material_indices[slot].specular_tint_sampler],
312#else // BINDLESS
313 pbr_bindings::specular_tint_texture,
314 pbr_bindings::specular_tint_sampler,
315#endif // BINDLESS
316#ifdef STANDARD_MATERIAL_SPECULAR_TINT_UV_B
317 uv_b,
318#else // STANDARD_MATERIAL_SPECULAR_TINT_UV_B
319 uv,
320#endif // STANDARD_MATERIAL_SPECULAR_TINT_UV_B
321#ifdef MESHLET_MESH_MATERIAL_PASS
322 bias.ddx_uv,
323 bias.ddy_uv,
324#else // MESHLET_MESH_MATERIAL_PASS
325 bias.mip_bias,
326#endif // MESHLET_MESH_MATERIAL_PASS
327 ).rgb;
328 pbr_input.material.reflectance *= specular_tint;
329 }
331#endif // VERTEX_UVS
332#endif // PBR_SPECULAR_TEXTURES_SUPPORTED
334 // emissive
335#ifdef BINDLESS
336 var emissive: vec4<f32> = pbr_bindings::material_array[material_indices[slot].material].emissive;
337#else // BINDLESS
338 var emissive: vec4<f32> = pbr_bindings::material.emissive;
339#endif // BINDLESS
341#ifdef VERTEX_UVS
342 if ((flags & pbr_types::STANDARD_MATERIAL_FLAGS_EMISSIVE_TEXTURE_BIT) != 0u) {
343 emissive = vec4<f32>(emissive.rgb *
344#ifdef MESHLET_MESH_MATERIAL_PASS
345 textureSampleGrad(
346#else // MESHLET_MESH_MATERIAL_PASS
347 textureSampleBias(
348#endif // MESHLET_MESH_MATERIAL_PASS
349#ifdef BINDLESS
350 bindless_textures_2d[material_indices[slot].emissive_texture],
351 bindless_samplers_filtering[material_indices[slot].emissive_sampler],
352#else // BINDLESS
353 pbr_bindings::emissive_texture,
354 pbr_bindings::emissive_sampler,
355#endif // BINDLESS
356#ifdef STANDARD_MATERIAL_EMISSIVE_UV_B
357 uv_b,
358#else
359 uv,
360#endif
361#ifdef MESHLET_MESH_MATERIAL_PASS
362 bias.ddx_uv,
363 bias.ddy_uv,
364#else // MESHLET_MESH_MATERIAL_PASS
365 bias.mip_bias,
366#endif // MESHLET_MESH_MATERIAL_PASS
367 ).rgb,
368 emissive.a);
369 }
370#endif
371 pbr_input.material.emissive = emissive;
373 // metallic and perceptual roughness
374#ifdef BINDLESS
375 var metallic: f32 = pbr_bindings::material_array[material_indices[slot].material].metallic;
376 var perceptual_roughness: f32 = pbr_bindings::material_array[material_indices[slot].material].perceptual_roughness;
377#else // BINDLESS
378 var metallic: f32 = pbr_bindings::material.metallic;
379 var perceptual_roughness: f32 = pbr_bindings::material.perceptual_roughness;
380#endif // BINDLESS
382#ifdef VERTEX_UVS
383 if ((flags & pbr_types::STANDARD_MATERIAL_FLAGS_METALLIC_ROUGHNESS_TEXTURE_BIT) != 0u) {
384 let metallic_roughness =
385#ifdef MESHLET_MESH_MATERIAL_PASS
386 textureSampleGrad(
387#else // MESHLET_MESH_MATERIAL_PASS
388 textureSampleBias(
389#endif // MESHLET_MESH_MATERIAL_PASS
390#ifdef BINDLESS
391 bindless_textures_2d[material_indices[slot].metallic_roughness_texture],
392 bindless_samplers_filtering[material_indices[slot].metallic_roughness_sampler],
393#else // BINDLESS
394 pbr_bindings::metallic_roughness_texture,
395 pbr_bindings::metallic_roughness_sampler,
396#endif // BINDLESS
397#ifdef STANDARD_MATERIAL_METALLIC_ROUGHNESS_UV_B
398 uv_b,
399#else
400 uv,
401#endif
402#ifdef MESHLET_MESH_MATERIAL_PASS
403 bias.ddx_uv,
404 bias.ddy_uv,
405#else // MESHLET_MESH_MATERIAL_PASS
406 bias.mip_bias,
407#endif // MESHLET_MESH_MATERIAL_PASS
408 );
409 // Sampling from GLTF standard channels for now
410 metallic *= metallic_roughness.b;
411 perceptual_roughness *= metallic_roughness.g;
412 }
413#endif
414 pbr_input.material.metallic = metallic;
415 pbr_input.material.perceptual_roughness = perceptual_roughness;
417 // Clearcoat factor
418#ifdef BINDLESS
419 pbr_input.material.clearcoat =
420 pbr_bindings::material_array[material_indices[slot].material].clearcoat;
421#else // BINDLESS
422 pbr_input.material.clearcoat = pbr_bindings::material.clearcoat;
423#endif // BINDLESS
425#ifdef VERTEX_UVS
426#ifdef PBR_MULTI_LAYER_MATERIAL_TEXTURES_SUPPORTED
427 if ((flags & pbr_types::STANDARD_MATERIAL_FLAGS_CLEARCOAT_TEXTURE_BIT) != 0u) {
428 pbr_input.material.clearcoat *=
429#ifdef MESHLET_MESH_MATERIAL_PASS
430 textureSampleGrad(
431#else // MESHLET_MESH_MATERIAL_PASS
432 textureSampleBias(
433#endif // MESHLET_MESH_MATERIAL_PASS
434#ifdef BINDLESS
435 bindless_textures_2d[material_indices[slot].clearcoat_texture],
436 bindless_samplers_filtering[material_indices[slot].clearcoat_sampler],
437#else // BINDLESS
438 pbr_bindings::clearcoat_texture,
439 pbr_bindings::clearcoat_sampler,
440#endif // BINDLESS
441#ifdef STANDARD_MATERIAL_CLEARCOAT_UV_B
442 uv_b,
443#else
444 uv,
445#endif
446#ifdef MESHLET_MESH_MATERIAL_PASS
447 bias.ddx_uv,
448 bias.ddy_uv,
449#else // MESHLET_MESH_MATERIAL_PASS
450 bias.mip_bias,
451#endif // MESHLET_MESH_MATERIAL_PASS
452 ).r;
453 }
454#endif // PBR_MULTI_LAYER_MATERIAL_TEXTURES_SUPPORTED
455#endif // VERTEX_UVS
457 // Clearcoat roughness
458#ifdef BINDLESS
459 pbr_input.material.clearcoat_perceptual_roughness =
460 pbr_bindings::material_array[material_indices[slot].material].clearcoat_perceptual_roughness;
461#else // BINDLESS
462 pbr_input.material.clearcoat_perceptual_roughness =
463 pbr_bindings::material.clearcoat_perceptual_roughness;
464#endif // BINDLESS
466#ifdef VERTEX_UVS
467#ifdef PBR_MULTI_LAYER_MATERIAL_TEXTURES_SUPPORTED
468 if ((flags & pbr_types::STANDARD_MATERIAL_FLAGS_CLEARCOAT_ROUGHNESS_TEXTURE_BIT) != 0u) {
469 pbr_input.material.clearcoat_perceptual_roughness *=
470#ifdef MESHLET_MESH_MATERIAL_PASS
471 textureSampleGrad(
472#else // MESHLET_MESH_MATERIAL_PASS
473 textureSampleBias(
474#endif // MESHLET_MESH_MATERIAL_PASS
475#ifdef BINDLESS
476 bindless_textures_2d[material_indices[slot].clearcoat_roughness_texture],
477 bindless_samplers_filtering[material_indices[slot].clearcoat_roughness_sampler],
478#else // BINDLESS
479 pbr_bindings::clearcoat_roughness_texture,
480 pbr_bindings::clearcoat_roughness_sampler,
481#endif // BINDLESS
482#ifdef STANDARD_MATERIAL_CLEARCOAT_ROUGHNESS_UV_B
483 uv_b,
484#else
485 uv,
486#endif
487#ifdef MESHLET_MESH_MATERIAL_PASS
488 bias.ddx_uv,
489 bias.ddy_uv,
490#else // MESHLET_MESH_MATERIAL_PASS
491 bias.mip_bias,
492#endif // MESHLET_MESH_MATERIAL_PASS
493 ).g;
494 }
495#endif // PBR_MULTI_LAYER_MATERIAL_TEXTURES_SUPPORTED
496#endif // VERTEX_UVS
498#ifdef BINDLESS
499 var specular_transmission: f32 = pbr_bindings::material_array[slot].specular_transmission;
500#else // BINDLESS
501 var specular_transmission: f32 = pbr_bindings::material.specular_transmission;
502#endif // BINDLESS
504#ifdef VERTEX_UVS
505#ifdef PBR_TRANSMISSION_TEXTURES_SUPPORTED
506 if ((flags & pbr_types::STANDARD_MATERIAL_FLAGS_SPECULAR_TRANSMISSION_TEXTURE_BIT) != 0u) {
507 specular_transmission *=
508#ifdef MESHLET_MESH_MATERIAL_PASS
509 textureSampleGrad(
510#else // MESHLET_MESH_MATERIAL_PASS
511 textureSampleBias(
512#endif // MESHLET_MESH_MATERIAL_PASS
513#ifdef BINDLESS
514 bindless_textures_2d[
515 material_indices[slot].specular_transmission_texture
516 ],
517 bindless_samplers_filtering[
518 material_indices[slot].specular_transmission_sampler
519 ],
520#else // BINDLESS
521 pbr_bindings::specular_transmission_texture,
522 pbr_bindings::specular_transmission_sampler,
523#endif // BINDLESS
524#ifdef STANDARD_MATERIAL_SPECULAR_TRANSMISSION_UV_B
525 uv_b,
526#else
527 uv,
528#endif
529#ifdef MESHLET_MESH_MATERIAL_PASS
530 bias.ddx_uv,
531 bias.ddy_uv,
532#else // MESHLET_MESH_MATERIAL_PASS
533 bias.mip_bias,
534#endif // MESHLET_MESH_MATERIAL_PASS
535 ).r;
536 }
537#endif
538#endif
539 pbr_input.material.specular_transmission = specular_transmission;
541#ifdef BINDLESS
542 var thickness: f32 = pbr_bindings::material_array[material_indices[slot].material].thickness;
543#else // BINDLESS
544 var thickness: f32 = pbr_bindings::material.thickness;
545#endif // BINDLESS
547#ifdef VERTEX_UVS
548#ifdef PBR_TRANSMISSION_TEXTURES_SUPPORTED
549 if ((flags & pbr_types::STANDARD_MATERIAL_FLAGS_THICKNESS_TEXTURE_BIT) != 0u) {
550 thickness *=
551#ifdef MESHLET_MESH_MATERIAL_PASS
552 textureSampleGrad(
553#else // MESHLET_MESH_MATERIAL_PASS
554 textureSampleBias(
555#endif // MESHLET_MESH_MATERIAL_PASS
556#ifdef BINDLESS
557 bindless_textures_2d[material_indices[slot].thickness_texture],
558 bindless_samplers_filtering[material_indices[slot].thickness_sampler],
559#else // BINDLESS
560 pbr_bindings::thickness_texture,
561 pbr_bindings::thickness_sampler,
562#endif // BINDLESS
563#ifdef STANDARD_MATERIAL_THICKNESS_UV_B
564 uv_b,
565#else
566 uv,
567#endif
568#ifdef MESHLET_MESH_MATERIAL_PASS
569 bias.ddx_uv,
570 bias.ddy_uv,
571#else // MESHLET_MESH_MATERIAL_PASS
572 bias.mip_bias,
573#endif // MESHLET_MESH_MATERIAL_PASS
574 ).g;
575 }
576#endif
577#endif
578 // scale thickness, accounting for non-uniform scaling (e.g. a “squished” mesh)
579 // TODO: Meshlet support
580#ifndef MESHLET_MESH_MATERIAL_PASS
581 thickness *= length(
582 (transpose(mesh[in.instance_index].world_from_local) * vec4(pbr_input.N, 0.0)).xyz
583 );
584#endif
585 pbr_input.material.thickness = thickness;
587#ifdef BINDLESS
588 var diffuse_transmission =
589 pbr_bindings::material_array[material_indices[slot].material].diffuse_transmission;
590#else // BINDLESS
591 var diffuse_transmission = pbr_bindings::material.diffuse_transmission;
592#endif // BINDLESS
594#ifdef VERTEX_UVS
595#ifdef PBR_TRANSMISSION_TEXTURES_SUPPORTED
596 if ((flags & pbr_types::STANDARD_MATERIAL_FLAGS_DIFFUSE_TRANSMISSION_TEXTURE_BIT) != 0u) {
597 diffuse_transmission *=
598#ifdef MESHLET_MESH_MATERIAL_PASS
599 textureSampleGrad(
600#else // MESHLET_MESH_MATERIAL_PASS
601 textureSampleBias(
602#endif // MESHLET_MESH_MATERIAL_PASS
603#ifdef BINDLESS
604 bindless_textures_2d[material_indices[slot].diffuse_transmission_texture],
605 bindless_samplers_filtering[material_indices[slot].diffuse_transmission_sampler],
606#else // BINDLESS
607 pbr_bindings::diffuse_transmission_texture,
608 pbr_bindings::diffuse_transmission_sampler,
609#endif // BINDLESS
610#ifdef STANDARD_MATERIAL_DIFFUSE_TRANSMISSION_UV_B
611 uv_b,
612#else
613 uv,
614#endif
615#ifdef MESHLET_MESH_MATERIAL_PASS
616 bias.ddx_uv,
617 bias.ddy_uv,
618#else // MESHLET_MESH_MATERIAL_PASS
619 bias.mip_bias,
620#endif // MESHLET_MESH_MATERIAL_PASS
621 ).a;
622 }
623#endif
624#endif
625 pbr_input.material.diffuse_transmission = diffuse_transmission;
627 var diffuse_occlusion: vec3<f32> = vec3(1.0);
628 var specular_occlusion: f32 = 1.0;
629#ifdef VERTEX_UVS
630 if ((flags & pbr_types::STANDARD_MATERIAL_FLAGS_OCCLUSION_TEXTURE_BIT) != 0u) {
631 diffuse_occlusion *=
632#ifdef MESHLET_MESH_MATERIAL_PASS
633 textureSampleGrad(
634#else // MESHLET_MESH_MATERIAL_PASS
635 textureSampleBias(
636#endif // MESHLET_MESH_MATERIAL_PASS
637#ifdef BINDLESS
638 bindless_textures_2d[material_indices[slot].occlusion_texture],
639 bindless_samplers_filtering[material_indices[slot].occlusion_sampler],
640#else // BINDLESS
641 pbr_bindings::occlusion_texture,
642 pbr_bindings::occlusion_sampler,
643#endif // BINDLESS
644#ifdef STANDARD_MATERIAL_OCCLUSION_UV_B
645 uv_b,
646#else
647 uv,
648#endif
649#ifdef MESHLET_MESH_MATERIAL_PASS
650 bias.ddx_uv,
651 bias.ddy_uv,
652#else // MESHLET_MESH_MATERIAL_PASS
653 bias.mip_bias,
654#endif // MESHLET_MESH_MATERIAL_PASS
655 ).r;
656 }
657#endif
658#ifdef SCREEN_SPACE_AMBIENT_OCCLUSION
659 let ssao = textureLoad(screen_space_ambient_occlusion_texture, vec2<i32>(in.position.xy), 0i).r;
660 let ssao_multibounce = ssao_multibounce(ssao, pbr_input.material.base_color.rgb);
661 diffuse_occlusion = min(diffuse_occlusion, ssao_multibounce);
662 // Use SSAO to estimate the specular occlusion.
663 // Lagarde and Rousiers 2014, "Moving Frostbite to Physically Based Rendering"
664 let roughness = lighting::perceptualRoughnessToRoughness(pbr_input.material.perceptual_roughness);
665 specular_occlusion = saturate(pow(NdotV + ssao, exp2(-16.0 * roughness - 1.0)) - 1.0 + ssao);
666#endif
667 pbr_input.diffuse_occlusion = diffuse_occlusion;
668 pbr_input.specular_occlusion = specular_occlusion;
670 // N (normal vector)
671#ifndef LOAD_PREPASS_NORMALS
673 pbr_input.N = normalize(pbr_input.world_normal);
674 pbr_input.clearcoat_N = pbr_input.N;
676#ifdef VERTEX_UVS
677#ifdef VERTEX_TANGENTS
679 let TBN = pbr_functions::calculate_tbn_mikktspace(pbr_input.world_normal, in.world_tangent);
681#ifdef STANDARD_MATERIAL_NORMAL_MAP
683 let Nt =
684#ifdef MESHLET_MESH_MATERIAL_PASS
685 textureSampleGrad(
686#else // MESHLET_MESH_MATERIAL_PASS
687 textureSampleBias(
688#endif // MESHLET_MESH_MATERIAL_PASS
689#ifdef BINDLESS
690 bindless_textures_2d[material_indices[slot].normal_map_texture],
691 bindless_samplers_filtering[material_indices[slot].normal_map_sampler],
692#else // BINDLESS
693 pbr_bindings::normal_map_texture,
694 pbr_bindings::normal_map_sampler,
695#endif // BINDLESS
696#ifdef STANDARD_MATERIAL_NORMAL_MAP_UV_B
697 uv_b,
698#else
699 uv,
700#endif
701#ifdef MESHLET_MESH_MATERIAL_PASS
702 bias.ddx_uv,
703 bias.ddy_uv,
704#else // MESHLET_MESH_MATERIAL_PASS
705 bias.mip_bias,
706#endif // MESHLET_MESH_MATERIAL_PASS
707 ).rgb;
709 pbr_input.N = pbr_functions::apply_normal_mapping(flags, TBN, double_sided, is_front, Nt);
711#endif // STANDARD_MATERIAL_NORMAL_MAP
713#ifdef STANDARD_MATERIAL_CLEARCOAT
715 // Note: `KHR_materials_clearcoat` specifies that, if there's no
716 // clearcoat normal map, we must set the normal to the mesh's normal,
717 // and not to the main layer's bumped normal.
719#ifdef STANDARD_MATERIAL_CLEARCOAT_NORMAL_MAP
721 let clearcoat_Nt =
722#ifdef MESHLET_MESH_MATERIAL_PASS
723 textureSampleGrad(
724#else // MESHLET_MESH_MATERIAL_PASS
725 textureSampleBias(
726#endif // MESHLET_MESH_MATERIAL_PASS
727#ifdef BINDLESS
728 bindless_textures_2d[material_indices[slot].clearcoat_normal_texture],
729 bindless_samplers_filtering[material_indices[slot].clearcoat_normal_sampler],
730#else // BINDLESS
731 pbr_bindings::clearcoat_normal_texture,
732 pbr_bindings::clearcoat_normal_sampler,
733#endif // BINDLESS
734#ifdef STANDARD_MATERIAL_CLEARCOAT_NORMAL_UV_B
735 uv_b,
736#else
737 uv,
738#endif
739#ifdef MESHLET_MESH_MATERIAL_PASS
740 bias.ddx_uv,
741 bias.ddy_uv,
742#else // MESHLET_MESH_MATERIAL_PASS
743 bias.mip_bias,
744#endif // MESHLET_MESH_MATERIAL_PASS
745 ).rgb;
747 pbr_input.clearcoat_N = pbr_functions::apply_normal_mapping(
748 flags,
749 TBN,
750 double_sided,
751 is_front,
752 clearcoat_Nt,
753 );
755#endif // STANDARD_MATERIAL_CLEARCOAT_NORMAL_MAP
757#endif // STANDARD_MATERIAL_CLEARCOAT
759#endif // VERTEX_TANGENTS
760#endif // VERTEX_UVS
762 // Take anisotropy into account.
763 //
764 // This code comes from the `KHR_materials_anisotropy` spec:
765 // <https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_materials_anisotropy/README.md#individual-lights>
766#ifdef PBR_ANISOTROPY_TEXTURE_SUPPORTED
767#ifdef VERTEX_TANGENTS
768#ifdef STANDARD_MATERIAL_ANISOTROPY
770#ifdef BINDLESS
771 var anisotropy_strength =
772 pbr_bindings::material_array[material_indices[slot].material].anisotropy_strength;
773 var anisotropy_direction =
774 pbr_bindings::material_array[material_indices[slot].material].anisotropy_rotation;
775#else // BINDLESS
776 var anisotropy_strength = pbr_bindings::material.anisotropy_strength;
777 var anisotropy_direction = pbr_bindings::material.anisotropy_rotation;
778#endif // BINDLESS
780 // Adjust based on the anisotropy map if there is one.
781 if ((flags & pbr_types::STANDARD_MATERIAL_FLAGS_ANISOTROPY_TEXTURE_BIT) != 0u) {
782 let anisotropy_texel =
783#ifdef MESHLET_MESH_MATERIAL_PASS
784 textureSampleGrad(
785#else // MESHLET_MESH_MATERIAL_PASS
786 textureSampleBias(
787#endif // MESHLET_MESH_MATERIAL_PASS
788#ifdef BINDLESS
789 bindless_textures_2d[material_indices[slot].anisotropy_texture],
790 bindless_samplers_filtering[material_indices[slot].anisotropy_sampler],
791#else // BINDLESS
792 pbr_bindings::anisotropy_texture,
793 pbr_bindings::anisotropy_sampler,
794#endif
795#ifdef STANDARD_MATERIAL_ANISOTROPY_UV_B
796 uv_b,
797#else // STANDARD_MATERIAL_ANISOTROPY_UV_B
798 uv,
799#endif // STANDARD_MATERIAL_ANISOTROPY_UV_B
800#ifdef MESHLET_MESH_MATERIAL_PASS
801 bias.ddx_uv,
802 bias.ddy_uv,
803#else // MESHLET_MESH_MATERIAL_PASS
804 bias.mip_bias,
805#endif // MESHLET_MESH_MATERIAL_PASS
806 ).rgb;
808 let anisotropy_direction_from_texture = normalize(anisotropy_texel.rg * 2.0 - 1.0);
809 // Rotate by the anisotropy direction.
810 anisotropy_direction =
811 mat2x2(anisotropy_direction.xy, anisotropy_direction.yx * vec2(-1.0, 1.0)) *
812 anisotropy_direction_from_texture;
813 anisotropy_strength *= anisotropy_texel.b;
814 }
816 pbr_input.anisotropy_strength = anisotropy_strength;
818 let anisotropy_T = normalize(TBN * vec3(anisotropy_direction, 0.0));
819 let anisotropy_B = normalize(cross(pbr_input.world_normal, anisotropy_T));
820 pbr_input.anisotropy_T = anisotropy_T;
821 pbr_input.anisotropy_B = anisotropy_B;
823#endif // STANDARD_MATERIAL_ANISOTROPY
824#endif // VERTEX_TANGENTS
825#endif // PBR_ANISOTROPY_TEXTURE_SUPPORTED
827#endif // LOAD_PREPASS_NORMALS
829// TODO: Meshlet support
830#ifdef LIGHTMAP
832#ifdef BINDLESS
833 let lightmap_exposure =
834 pbr_bindings::material_array[material_indices[slot].material].lightmap_exposure;
835#else // BINDLESS
836 let lightmap_exposure = pbr_bindings::material.lightmap_exposure;
837#endif // BINDLESS
839 pbr_input.lightmap_light = lightmap(in.uv_b, lightmap_exposure, in.instance_index);
840#endif
841 }
843 return pbr_input;
Contents