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#else // BINDLESS
90 let flags = pbr_bindings::material.flags;
91 let base_color = pbr_bindings::material.base_color;
92 let deferred_lighting_pass_id = pbr_bindings::material.deferred_lighting_pass_id;
93#endif
95 let double_sided = (flags & pbr_types::STANDARD_MATERIAL_FLAGS_DOUBLE_SIDED_BIT) != 0u;
97 var pbr_input: pbr_types::PbrInput = pbr_input_from_vertex_output(in, is_front, double_sided);
98 pbr_input.material.flags = flags;
99 pbr_input.material.base_color *= base_color;
100 pbr_input.material.deferred_lighting_pass_id = deferred_lighting_pass_id;
102 // Neubelt and Pettineo 2013, "Crafting a Next-gen Material Pipeline for The Order: 1886"
103 let NdotV = max(dot(pbr_input.N, pbr_input.V), 0.0001);
105 // Fill in the sample bias so we can sample from textures.
106 var bias: SampleBias;
107#ifdef MESHLET_MESH_MATERIAL_PASS
108 bias.ddx_uv = in.ddx_uv;
109 bias.ddy_uv = in.ddy_uv;
110#else // MESHLET_MESH_MATERIAL_PASS
111 bias.mip_bias = view.mip_bias;
112#endif // MESHLET_MESH_MATERIAL_PASS
114// TODO: Transforming UVs mean we need to apply derivative chain rule for meshlet mesh material pass
115#ifdef VERTEX_UVS
117#ifdef BINDLESS
118 let uv_transform = pbr_bindings::material_array[material_indices[slot].material].uv_transform;
119#else // BINDLESS
120 let uv_transform = pbr_bindings::material.uv_transform;
121#endif // BINDLESS
123pbr_input.material.uv_transform = uv_transform;
125#ifdef VERTEX_UVS_A
126 var uv = (uv_transform * vec3(in.uv, 1.0)).xy;
127#endif
129// TODO: Transforming UVs mean we need to apply derivative chain rule for meshlet mesh material pass
130#ifdef VERTEX_UVS_B
131 var uv_b = (uv_transform * vec3(in.uv_b, 1.0)).xy;
132#else
133 var uv_b = uv;
134#endif
136#ifdef VERTEX_TANGENTS
137 if ((flags & pbr_types::STANDARD_MATERIAL_FLAGS_DEPTH_MAP_BIT) != 0u) {
138 let V = pbr_input.V;
139 let TBN = pbr_functions::calculate_tbn_mikktspace(in.world_normal, in.world_tangent);
140 let T = TBN[0];
141 let B = TBN[1];
142 let N = TBN[2];
143 // Transform V from fragment to camera in world space to tangent space.
144 let Vt = vec3(dot(V, T), dot(V, B), dot(V, N));
145#ifdef VERTEX_UVS_A
146 // TODO: Transforming UVs mean we need to apply derivative chain rule for meshlet mesh material pass
147 uv = parallaxed_uv(
148#ifdef BINDLESS
149 pbr_bindings::material_array[material_indices[slot].material].parallax_depth_scale,
150 pbr_bindings::material_array[material_indices[slot].material].max_parallax_layer_count,
151 pbr_bindings::material_array[material_indices[slot].material].max_relief_mapping_search_steps,
152#else // BINDLESS
153 pbr_bindings::material.parallax_depth_scale,
154 pbr_bindings::material.max_parallax_layer_count,
155 pbr_bindings::material.max_relief_mapping_search_steps,
156#endif // BINDLESS
157 uv,
158 // Flip the direction of Vt to go toward the surface to make the
159 // parallax mapping algorithm easier to understand and reason
160 // about.
161 -Vt,
162 slot,
163 );
164#endif
166#ifdef VERTEX_UVS_B
167 // TODO: Transforming UVs mean we need to apply derivative chain rule for meshlet mesh material pass
168 uv_b = parallaxed_uv(
169#ifdef BINDLESS
170 pbr_bindings::material_array[material_indices[slot].material].parallax_depth_scale,
171 pbr_bindings::material_array[material_indices[slot].material].max_parallax_layer_count,
172 pbr_bindings::material_array[material_indices[slot].material].max_relief_mapping_search_steps,
173#else // BINDLESS
174 pbr_bindings::material.parallax_depth_scale,
175 pbr_bindings::material.max_parallax_layer_count,
176 pbr_bindings::material.max_relief_mapping_search_steps,
177#endif // BINDLESS
178 uv_b,
179 // Flip the direction of Vt to go toward the surface to make the
180 // parallax mapping algorithm easier to understand and reason
181 // about.
182 -Vt,
183 slot,
184 );
185#else
186 uv_b = uv;
187#endif
188 }
189#endif // VERTEX_TANGENTS
191 if ((flags & pbr_types::STANDARD_MATERIAL_FLAGS_BASE_COLOR_TEXTURE_BIT) != 0u) {
192 pbr_input.material.base_color *=
193#ifdef MESHLET_MESH_MATERIAL_PASS
194 textureSampleGrad(
195#else // MESHLET_MESH_MATERIAL_PASS
196 textureSampleBias(
197#endif // MESHLET_MESH_MATERIAL_PASS
198#ifdef BINDLESS
199 bindless_textures_2d[material_indices[slot].base_color_texture],
200 bindless_samplers_filtering[material_indices[slot].base_color_sampler],
201#else // BINDLESS
202 pbr_bindings::base_color_texture,
203 pbr_bindings::base_color_sampler,
204#endif // BINDLESS
205#ifdef STANDARD_MATERIAL_BASE_COLOR_UV_B
206 uv_b,
207#else
208 uv,
209#endif
210#ifdef MESHLET_MESH_MATERIAL_PASS
211 bias.ddx_uv,
212 bias.ddy_uv,
213#else // MESHLET_MESH_MATERIAL_PASS
214 bias.mip_bias,
215#endif // MESHLET_MESH_MATERIAL_PASS
216 );
218#ifdef ALPHA_TO_COVERAGE
219 // Sharpen alpha edges.
220 //
221 // https://bgolus.medium.com/anti-aliased-alpha-test-the-esoteric-alpha-to-coverage-8b177335ae4f
222 let alpha_mode = flags & pbr_types::STANDARD_MATERIAL_FLAGS_ALPHA_MODE_RESERVED_BITS;
223 if alpha_mode == pbr_types::STANDARD_MATERIAL_FLAGS_ALPHA_MODE_ALPHA_TO_COVERAGE {
225#ifdef BINDLESS
226 let alpha_cutoff = pbr_bindings::material_array[material_indices[slot].material].alpha_cutoff;
227#else // BINDLESS
228 let alpha_cutoff = pbr_bindings::material.alpha_cutoff;
229#endif // BINDLESS
231 pbr_input.material.base_color.a = (pbr_input.material.base_color.a - alpha_cutoff) /
232 max(fwidth(pbr_input.material.base_color.a), 0.0001) + 0.5;
233 }
234#endif // ALPHA_TO_COVERAGE
236 }
237#endif // VERTEX_UVS
239 pbr_input.material.flags = flags;
241 // NOTE: Unlit bit not set means == 0 is true, so the true case is if lit
242 if ((flags & pbr_types::STANDARD_MATERIAL_FLAGS_UNLIT_BIT) == 0u) {
243#ifdef BINDLESS
244 pbr_input.material.ior = pbr_bindings::material_array[material_indices[slot].material].ior;
245 pbr_input.material.attenuation_color =
246 pbr_bindings::material_array[material_indices[slot].material].attenuation_color;
247 pbr_input.material.attenuation_distance =
248 pbr_bindings::material_array[material_indices[slot].material].attenuation_distance;
249 pbr_input.material.alpha_cutoff =
250 pbr_bindings::material_array[material_indices[slot].material].alpha_cutoff;
251#else // BINDLESS
252 pbr_input.material.ior = pbr_bindings::material.ior;
253 pbr_input.material.attenuation_color = pbr_bindings::material.attenuation_color;
254 pbr_input.material.attenuation_distance = pbr_bindings::material.attenuation_distance;
255 pbr_input.material.alpha_cutoff = pbr_bindings::material.alpha_cutoff;
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