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.
1import bevy_render::bindless::{bindless_samplers_filtering, bindless_textures_2d};
3import package::{
4 render::{
5 pbr_functions,
6 pbr_functions::SampleBias,
7 pbr_bindings,
8 pbr_types,
9 pbr_lighting as lighting,
10 mesh_bindings::mesh,
11 mesh_view_bindings::view,
12 parallax_mapping::parallaxed_uv,
13 },
14 prepass::utils as prepass_utils,
15 lightmap::lightmap,
16};
18@if(SCREEN_SPACE_AMBIENT_OCCLUSION)
19import package::render::mesh_view_bindings::screen_space_ambient_occlusion_texture;
20@if(SCREEN_SPACE_AMBIENT_OCCLUSION)
21import package::ssao::utils::ssao_multibounce;
23@if(MESHLET_MESH_MATERIAL_PASS)
24import package::meshlet::visibility_buffer_resolve::VertexOutput;
25@elif(PREPASS_PIPELINE)
26import package::prepass::io::VertexOutput;
27@else
28import package::render::forward_io::VertexOutput;
30@if(BINDLESS)
31import package::render::pbr_bindings::material_indices;
33/// prepare a basic PbrInput from the vertex stage output, mesh binding and view binding
34fn pbr_input_from_vertex_output(
35 in: VertexOutput,
36 is_front: bool,
37 double_sided: bool,
38) -> pbr_types::PbrInput {
39 var pbr_input: pbr_types::PbrInput = pbr_types::pbr_input_new();
41@if(MESHLET_MESH_MATERIAL_PASS)
42 pbr_input.flags = in.mesh_flags;
43@else
44 pbr_input.flags = mesh[in.instance_index].flags;
46 pbr_input.is_orthographic = view.clip_from_view[3].w == 1.0;
47 pbr_input.V = pbr_functions::calculate_view(in.world_position, pbr_input.is_orthographic);
48 pbr_input.frag_coord = in.position;
49 pbr_input.world_position = in.world_position;
51@if(VERTEX_COLORS)
52 pbr_input.material.base_color = in.color;
54 let is_logically_front = pbr_functions::winding_corrected_front_facing(pbr_input.flags, is_front);
55 pbr_input.world_normal = pbr_functions::prepare_world_normal(
56 in.world_normal,
57 double_sided,
58 is_logically_front,
59 );
61@if(LOAD_PREPASS_NORMALS)
62 pbr_input.N = prepass_utils::prepass_normal(in.position, 0u);
63@else
64 pbr_input.N = normalize(pbr_input.world_normal);
66 return pbr_input;
69/// Prepare a full PbrInput by sampling all textures to resolve
70/// the material members
71fn pbr_input_from_standard_material(
72 in: VertexOutput,
73 is_front: bool,
74) -> pbr_types::PbrInput {
75@if(MESHLET_MESH_MATERIAL_PASS)
76 let slot = in.material_bind_group_slot;
77@else // MESHLET_MESH_MATERIAL_PASS
78 let slot = mesh[in.instance_index].material_and_lightmap_bind_group_slot & 0xffffu;
79@if(BINDLESS)
80 let flags = pbr_bindings::material_array[material_indices[slot].material].flags;
81@else
82 let flags = pbr_bindings::material.flags;
83@if(BINDLESS)
84 let base_color = pbr_bindings::material_array[material_indices[slot].material].base_color;
85@else
86 let base_color = pbr_bindings::material.base_color;
87@if(BINDLESS)
88 let deferred_lighting_pass_id =
89 pbr_bindings::material_array[material_indices[slot].material].deferred_lighting_pass_id;
90@else
91 let deferred_lighting_pass_id = pbr_bindings::material.deferred_lighting_pass_id;
92@if(BINDLESS)
93 let alpha_cutoff = pbr_bindings::material_array[material_indices[slot].material].alpha_cutoff;
94@else
95 let alpha_cutoff = pbr_bindings::material.alpha_cutoff;
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;
103 let is_logically_front = pbr_functions::winding_corrected_front_facing(pbr_input.flags, is_front);
105 // Neubelt and Pettineo 2013, "Crafting a Next-gen Material Pipeline for The Order: 1886"
106 let NdotV = max(dot(pbr_input.N, pbr_input.V), 0.0001);
108 // Fill in the sample bias so we can sample from textures.
109 var bias: SampleBias;
110@if(MESHLET_MESH_MATERIAL_PASS) {
111 // Apply mip bias by scaling the gradients used by textureSampleGrad.
112 let mip_scale = exp2(view.mip_bias);
113 bias.ddx_uv = in.ddx_uv * mip_scale;
114 bias.ddy_uv = in.ddy_uv * mip_scale;
116@else {
117 bias.mip_bias = view.mip_bias;
120// TODO: Transforming UVs mean we need to apply derivative chain rule for meshlet mesh material pass
122@if(VERTEX_UVS && BINDLESS)
123 let uv_transform = pbr_bindings::material_array[material_indices[slot].material].uv_transform;
124@elif(VERTEX_UVS)
125 let uv_transform = pbr_bindings::material.uv_transform;
127@if(VERTEX_UVS)
128pbr_input.material.uv_transform = uv_transform;
130@if(VERTEX_UVS && VERTEX_UVS_A)
131 var uv = (uv_transform * vec3(in.uv, 1.0)).xy;
133// TODO: Transforming UVs mean we need to apply derivative chain rule for meshlet mesh material pass
134@if(VERTEX_UVS && VERTEX_UVS_B)
135 var uv_b = (uv_transform * vec3(in.uv_b, 1.0)).xy;
136@elif(VERTEX_UVS)
137 var uv_b = uv;
139@if(VERTEX_UVS && VERTEX_TANGENTS)
140 if ((flags & pbr_types::STANDARD_MATERIAL_FLAGS_DEPTH_MAP_BIT) != 0u) {
141 let V = pbr_input.V;
142 let TBN = pbr_functions::calculate_tbn_mikktspace(in.world_normal, in.world_tangent);
143 let T = TBN[0];
144 let B = TBN[1];
145 let N = TBN[2];
146 // Transform V from fragment to camera in world space to tangent space.
147 let Vt = vec3(dot(V, T), dot(V, B), dot(V, N));
148 @if(BINDLESS)
149 let parallax_depth_scale = pbr_bindings::material_array[material_indices[slot].material].parallax_depth_scale;
150 @else
151 let parallax_depth_scale = pbr_bindings::material.parallax_depth_scale;
152 @if(BINDLESS)
153 let max_parallax_layer_count = pbr_bindings::material_array[material_indices[slot].material].max_parallax_layer_count;
154 @else
155 let max_parallax_layer_count = pbr_bindings::material.max_parallax_layer_count;
156 @if(BINDLESS)
157 let max_relief_mapping_search_steps = pbr_bindings::material_array[material_indices[slot].material].max_relief_mapping_search_steps;
158 @else
159 let max_relief_mapping_search_steps = pbr_bindings::material.max_relief_mapping_search_steps;
160@if(VERTEX_UVS_A) {
161 // TODO: Transforming UVs mean we need to apply derivative chain rule for meshlet mesh material pass
162 uv = parallaxed_uv(
163 parallax_depth_scale,
164 max_parallax_layer_count,
165 max_relief_mapping_search_steps,
166 uv,
167 // Flip the direction of Vt to go toward the surface to make the
168 // parallax mapping algorithm easier to understand and reason
169 // about.
170 -Vt,
171 slot,
172 );
175@if(VERTEX_UVS_B) {
176 // TODO: Transforming UVs mean we need to apply derivative chain rule for meshlet mesh material pass
177 uv_b = parallaxed_uv(
178 parallax_depth_scale,
179 max_parallax_layer_count,
180 max_relief_mapping_search_steps,
181 uv_b,
182 // Flip the direction of Vt to go toward the surface to make the
183 // parallax mapping algorithm easier to understand and reason
184 // about.
185 -Vt,
186 slot,
187 );
189@else
190 uv_b = uv;
191 }
193@if(VERTEX_UVS)
194 if ((flags & pbr_types::STANDARD_MATERIAL_FLAGS_BASE_COLOR_TEXTURE_BIT) != 0u) {
195 @if(BINDLESS)
196 let texture = bindless_textures_2d[material_indices[slot].base_color_texture];
197 @else
198 let texture = pbr_bindings::base_color_texture;
199 @if(BINDLESS)
200 let sampler_ = bindless_samplers_filtering[material_indices[slot].base_color_sampler];
201 @else
202 let sampler_ = pbr_bindings::base_color_sampler;
203 @if(STANDARD_MATERIAL_BASE_COLOR_UV_B)
204 let coords = uv_b;
205 @else
206 let coords = uv;
207 @if(MESHLET_MESH_MATERIAL_PASS)
208 pbr_input.material.base_color *= textureSampleGrad(texture, sampler_, coords, bias.ddx_uv, bias.ddy_uv);
209 @else
210 pbr_input.material.base_color *= textureSampleBias(texture, sampler_, coords, bias.mip_bias);
212@if(ALPHA_TO_COVERAGE) {
213 // Sharpen alpha edges.
214 //
215 // https://bgolus.medium.com/anti-aliased-alpha-test-the-esoteric-alpha-to-coverage-8b177335ae4f
216 let alpha_mode = flags & pbr_types::STANDARD_MATERIAL_FLAGS_ALPHA_MODE_RESERVED_BITS;
217 if alpha_mode == pbr_types::STANDARD_MATERIAL_FLAGS_ALPHA_MODE_ALPHA_TO_COVERAGE {
219@if(BINDLESS)
220 let alpha_cutoff = pbr_bindings::material_array[material_indices[slot].material].alpha_cutoff;
221@else
222 let alpha_cutoff = pbr_bindings::material.alpha_cutoff;
224 pbr_input.material.base_color.a = (pbr_input.material.base_color.a - alpha_cutoff) /
225 max(fwidth(pbr_input.material.base_color.a), 0.0001) + 0.5;
226 }
229 }
231 pbr_input.material.flags = flags;
232 pbr_input.material.alpha_cutoff = alpha_cutoff;
234 // NOTE: Unlit bit not set means == 0 is true, so the true case is if lit
235 if ((flags & pbr_types::STANDARD_MATERIAL_FLAGS_UNLIT_BIT) == 0u) {
236@if(BINDLESS) {
237 pbr_input.material.ior = pbr_bindings::material_array[material_indices[slot].material].ior;
238 pbr_input.material.attenuation_color =
239 pbr_bindings::material_array[material_indices[slot].material].attenuation_color;
240 pbr_input.material.attenuation_distance =
241 pbr_bindings::material_array[material_indices[slot].material].attenuation_distance;
243@else {
244 pbr_input.material.ior = pbr_bindings::material.ior;
245 pbr_input.material.attenuation_color = pbr_bindings::material.attenuation_color;
246 pbr_input.material.attenuation_distance = pbr_bindings::material.attenuation_distance;
249 // reflectance
250@if(BINDLESS)
251 pbr_input.material.reflectance =
252 pbr_bindings::material_array[material_indices[slot].material].reflectance;
253@else
254 pbr_input.material.reflectance = pbr_bindings::material.reflectance;
256@if(PBR_SPECULAR_TEXTURES_SUPPORTED && VERTEX_UVS) {
258 // Specular texture
259 if ((flags & pbr_types::STANDARD_MATERIAL_FLAGS_SPECULAR_TEXTURE_BIT) != 0u) {
260 @if(BINDLESS)
261 let texture = bindless_textures_2d[material_indices[slot].specular_texture];
262 @else
263 let texture = pbr_bindings::specular_texture;
264 @if(BINDLESS)
265 let sampler_ = bindless_samplers_filtering[material_indices[slot].specular_sampler];
266 @else
267 let sampler_ = pbr_bindings::specular_sampler;
268 @if(STANDARD_MATERIAL_SPECULAR_UV_B)
269 let coords = uv_b;
270 @else
271 let coords = uv;
272 @if(MESHLET_MESH_MATERIAL_PASS)
273 let specular = textureSampleGrad(texture, sampler_, coords, bias.ddx_uv, bias.ddy_uv).a;
274 @else
275 let specular = textureSampleBias(texture, sampler_, coords, bias.mip_bias).a;
276 // This 0.5 factor is from the `KHR_materials_specular` specification:
277 // <https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_materials_specular#materials-with-reflectance-parameter>
278 pbr_input.material.reflectance *= specular * 0.5;
279 }
281 // Specular tint texture
282 if ((flags & pbr_types::STANDARD_MATERIAL_FLAGS_SPECULAR_TINT_TEXTURE_BIT) != 0u) {
283 @if(BINDLESS)
284 let texture = bindless_textures_2d[material_indices[slot].specular_tint_texture];
285 @else
286 let texture = pbr_bindings::specular_tint_texture;
287 @if(BINDLESS)
288 let sampler_ = bindless_samplers_filtering[material_indices[slot].specular_tint_sampler];
289 @else
290 let sampler_ = pbr_bindings::specular_tint_sampler;
291 @if(STANDARD_MATERIAL_SPECULAR_TINT_UV_B)
292 let coords = uv_b;
293 @else
294 let coords = uv;
295 @if(MESHLET_MESH_MATERIAL_PASS)
296 let specular_tint = textureSampleGrad(texture, sampler_, coords, bias.ddx_uv, bias.ddy_uv).rgb;
297 @else
298 let specular_tint = textureSampleBias(texture, sampler_, coords, bias.mip_bias).rgb;
299 pbr_input.material.reflectance *= specular_tint;
300 }
304 // emissive
305@if(BINDLESS)
306 var emissive: vec4<f32> = pbr_bindings::material_array[material_indices[slot].material].emissive;
307@else
308 var emissive: vec4<f32> = pbr_bindings::material.emissive;
310@if(VERTEX_UVS)
311 if ((flags & pbr_types::STANDARD_MATERIAL_FLAGS_EMISSIVE_TEXTURE_BIT) != 0u) {
312 @if(BINDLESS)
313 let texture = bindless_textures_2d[material_indices[slot].emissive_texture];
314 @else
315 let texture = pbr_bindings::emissive_texture;
316 @if(BINDLESS)
317 let sampler_ = bindless_samplers_filtering[material_indices[slot].emissive_sampler];
318 @else
319 let sampler_ = pbr_bindings::emissive_sampler;
320 @if(STANDARD_MATERIAL_EMISSIVE_UV_B)
321 let coords = uv_b;
322 @else
323 let coords = uv;
324 @if(MESHLET_MESH_MATERIAL_PASS)
325 emissive = vec4<f32>(emissive.rgb * textureSampleGrad(texture, sampler_, coords, bias.ddx_uv, bias.ddy_uv).rgb, emissive.a);
326 @else
327 emissive = vec4<f32>(emissive.rgb * textureSampleBias(texture, sampler_, coords, bias.mip_bias).rgb, emissive.a);
328 }
329 pbr_input.material.emissive = emissive;
331 // metallic and perceptual roughness
332@if(BINDLESS)
333 var metallic: f32 = pbr_bindings::material_array[material_indices[slot].material].metallic;
334@else
335 var metallic: f32 = pbr_bindings::material.metallic;
336@if(BINDLESS)
337 var perceptual_roughness: f32 = pbr_bindings::material_array[material_indices[slot].material].perceptual_roughness;
338@else
339 var perceptual_roughness: f32 = pbr_bindings::material.perceptual_roughness;
341@if(VERTEX_UVS)
342 if ((flags & pbr_types::STANDARD_MATERIAL_FLAGS_METALLIC_ROUGHNESS_TEXTURE_BIT) != 0u) {
343 @if(BINDLESS)
344 let texture = bindless_textures_2d[material_indices[slot].metallic_roughness_texture];
345 @else
346 let texture = pbr_bindings::metallic_roughness_texture;
347 @if(BINDLESS)
348 let sampler_ = bindless_samplers_filtering[material_indices[slot].metallic_roughness_sampler];
349 @else
350 let sampler_ = pbr_bindings::metallic_roughness_sampler;
351 @if(STANDARD_MATERIAL_METALLIC_ROUGHNESS_UV_B)
352 let coords = uv_b;
353 @else
354 let coords = uv;
355 @if(MESHLET_MESH_MATERIAL_PASS)
356 let metallic_roughness = textureSampleGrad(texture, sampler_, coords, bias.ddx_uv, bias.ddy_uv);
357 @else
358 let metallic_roughness = textureSampleBias(texture, sampler_, coords, bias.mip_bias);
359 if ((flags & pbr_types::STANDARD_MATERIAL_FLAGS_METALLIC_ROUGHNESS_RG_BIT) != 0u) {
360 perceptual_roughness *= metallic_roughness.r;
361 metallic *= metallic_roughness.g;
362 } else {
363 // Sampling from GLTF standard channels
364 perceptual_roughness *= metallic_roughness.g;
365 metallic *= metallic_roughness.b;
366 }
367 }
368 pbr_input.material.metallic = metallic;
369 pbr_input.material.perceptual_roughness = perceptual_roughness;
371 // Clearcoat factor
372@if(BINDLESS)
373 pbr_input.material.clearcoat =
374 pbr_bindings::material_array[material_indices[slot].material].clearcoat;
375@else
376 pbr_input.material.clearcoat = pbr_bindings::material.clearcoat;
378@if(VERTEX_UVS && PBR_MULTI_LAYER_MATERIAL_TEXTURES_SUPPORTED)
379 if ((flags & pbr_types::STANDARD_MATERIAL_FLAGS_CLEARCOAT_TEXTURE_BIT) != 0u) {
380 @if(BINDLESS)
381 let texture = bindless_textures_2d[material_indices[slot].clearcoat_texture];
382 @else
383 let texture = pbr_bindings::clearcoat_texture;
384 @if(BINDLESS)
385 let sampler_ = bindless_samplers_filtering[material_indices[slot].clearcoat_sampler];
386 @else
387 let sampler_ = pbr_bindings::clearcoat_sampler;
388 @if(STANDARD_MATERIAL_CLEARCOAT_UV_B)
389 let coords = uv_b;
390 @else
391 let coords = uv;
392 @if(MESHLET_MESH_MATERIAL_PASS)
393 pbr_input.material.clearcoat *= textureSampleGrad(texture, sampler_, coords, bias.ddx_uv, bias.ddy_uv).r;
394 @else
395 pbr_input.material.clearcoat *= textureSampleBias(texture, sampler_, coords, bias.mip_bias).r;
396 }
398 // Clearcoat roughness
399@if(BINDLESS)
400 pbr_input.material.clearcoat_perceptual_roughness =
401 pbr_bindings::material_array[material_indices[slot].material].clearcoat_perceptual_roughness;
402@else
403 pbr_input.material.clearcoat_perceptual_roughness =
404 pbr_bindings::material.clearcoat_perceptual_roughness;
406@if(VERTEX_UVS && PBR_MULTI_LAYER_MATERIAL_TEXTURES_SUPPORTED)
407 if ((flags & pbr_types::STANDARD_MATERIAL_FLAGS_CLEARCOAT_ROUGHNESS_TEXTURE_BIT) != 0u) {
408 @if(BINDLESS)
409 let texture = bindless_textures_2d[material_indices[slot].clearcoat_roughness_texture];
410 @else
411 let texture = pbr_bindings::clearcoat_roughness_texture;
412 @if(BINDLESS)
413 let sampler_ = bindless_samplers_filtering[material_indices[slot].clearcoat_roughness_sampler];
414 @else
415 let sampler_ = pbr_bindings::clearcoat_roughness_sampler;
416 @if(STANDARD_MATERIAL_CLEARCOAT_ROUGHNESS_UV_B)
417 let coords = uv_b;
418 @else
419 let coords = uv;
420 @if(MESHLET_MESH_MATERIAL_PASS)
421 pbr_input.material.clearcoat_perceptual_roughness *= textureSampleGrad(texture, sampler_, coords, bias.ddx_uv, bias.ddy_uv).g;
422 @else
423 pbr_input.material.clearcoat_perceptual_roughness *= textureSampleBias(texture, sampler_, coords, bias.mip_bias).g;
424 }
426@if(BINDLESS)
427 var specular_transmission: f32 =
428 pbr_bindings::material_array[material_indices[slot].material].specular_transmission;
429@else
430 var specular_transmission: f32 = pbr_bindings::material.specular_transmission;
432@if(VERTEX_UVS && PBR_TRANSMISSION_TEXTURES_SUPPORTED)
433 if ((flags & pbr_types::STANDARD_MATERIAL_FLAGS_SPECULAR_TRANSMISSION_TEXTURE_BIT) != 0u) {
434 @if(BINDLESS)
435 let texture = bindless_textures_2d[
436 material_indices[slot].specular_transmission_texture
437 ];
438 @else
439 let texture = pbr_bindings::specular_transmission_texture;
440 @if(BINDLESS)
441 let sampler_ = bindless_samplers_filtering[
442 material_indices[slot].specular_transmission_sampler
443 ];
444 @else
445 let sampler_ = pbr_bindings::specular_transmission_sampler;
446 @if(STANDARD_MATERIAL_SPECULAR_TRANSMISSION_UV_B)
447 let coords = uv_b;
448 @else
449 let coords = uv;
450 @if(MESHLET_MESH_MATERIAL_PASS)
451 specular_transmission *= textureSampleGrad(texture, sampler_, coords, bias.ddx_uv, bias.ddy_uv).r;
452 @else
453 specular_transmission *= textureSampleBias(texture, sampler_, coords, bias.mip_bias).r;
454 }
455 pbr_input.material.specular_transmission = specular_transmission;
457@if(BINDLESS)
458 var thickness: f32 = pbr_bindings::material_array[material_indices[slot].material].thickness;
459@else
460 var thickness: f32 = pbr_bindings::material.thickness;
462@if(VERTEX_UVS && PBR_TRANSMISSION_TEXTURES_SUPPORTED)
463 if ((flags & pbr_types::STANDARD_MATERIAL_FLAGS_THICKNESS_TEXTURE_BIT) != 0u) {
464 @if(BINDLESS)
465 let texture = bindless_textures_2d[material_indices[slot].thickness_texture];
466 @else
467 let texture = pbr_bindings::thickness_texture;
468 @if(BINDLESS)
469 let sampler_ = bindless_samplers_filtering[material_indices[slot].thickness_sampler];
470 @else
471 let sampler_ = pbr_bindings::thickness_sampler;
472 @if(STANDARD_MATERIAL_THICKNESS_UV_B)
473 let coords = uv_b;
474 @else
475 let coords = uv;
476 @if(MESHLET_MESH_MATERIAL_PASS)
477 thickness *= textureSampleGrad(texture, sampler_, coords, bias.ddx_uv, bias.ddy_uv).g;
478 @else
479 thickness *= textureSampleBias(texture, sampler_, coords, bias.mip_bias).g;
480 }
481 // scale thickness, accounting for non-uniform scaling (e.g. a “squished” mesh)
482 // TODO: Meshlet support
483@if(!MESHLET_MESH_MATERIAL_PASS)
484 thickness *= length(
485 (transpose(mesh[in.instance_index].world_from_local) * vec4(pbr_input.N, 0.0)).xyz
486 );
487 pbr_input.material.thickness = thickness;
489@if(BINDLESS)
490 var diffuse_transmission =
491 pbr_bindings::material_array[material_indices[slot].material].diffuse_transmission;
492@else
493 var diffuse_transmission = pbr_bindings::material.diffuse_transmission;
495@if(VERTEX_UVS && PBR_TRANSMISSION_TEXTURES_SUPPORTED)
496 if ((flags & pbr_types::STANDARD_MATERIAL_FLAGS_DIFFUSE_TRANSMISSION_TEXTURE_BIT) != 0u) {
497 @if(BINDLESS)
498 let texture = bindless_textures_2d[material_indices[slot].diffuse_transmission_texture];
499 @else
500 let texture = pbr_bindings::diffuse_transmission_texture;
501 @if(BINDLESS)
502 let sampler_ = bindless_samplers_filtering[material_indices[slot].diffuse_transmission_sampler];
503 @else
504 let sampler_ = pbr_bindings::diffuse_transmission_sampler;
505 @if(STANDARD_MATERIAL_DIFFUSE_TRANSMISSION_UV_B)
506 let coords = uv_b;
507 @else
508 let coords = uv;
509 @if(MESHLET_MESH_MATERIAL_PASS)
510 diffuse_transmission *= textureSampleGrad(texture, sampler_, coords, bias.ddx_uv, bias.ddy_uv).a;
511 @else
512 diffuse_transmission *= textureSampleBias(texture, sampler_, coords, bias.mip_bias).a;
513 }
514 pbr_input.material.diffuse_transmission = diffuse_transmission;
516 var diffuse_occlusion: vec3<f32> = vec3(1.0);
517 var specular_occlusion: f32 = 1.0;
518@if(VERTEX_UVS)
519 if ((flags & pbr_types::STANDARD_MATERIAL_FLAGS_OCCLUSION_TEXTURE_BIT) != 0u) {
520 @if(BINDLESS)
521 let texture = bindless_textures_2d[material_indices[slot].occlusion_texture];
522 @else
523 let texture = pbr_bindings::occlusion_texture;
524 @if(BINDLESS)
525 let sampler_ = bindless_samplers_filtering[material_indices[slot].occlusion_sampler];
526 @else
527 let sampler_ = pbr_bindings::occlusion_sampler;
528 @if(STANDARD_MATERIAL_OCCLUSION_UV_B)
529 let coords = uv_b;
530 @else
531 let coords = uv;
532 @if(MESHLET_MESH_MATERIAL_PASS)
533 diffuse_occlusion *= textureSampleGrad(texture, sampler_, coords, bias.ddx_uv, bias.ddy_uv).r;
534 @else
535 diffuse_occlusion *= textureSampleBias(texture, sampler_, coords, bias.mip_bias).r;
536 }
537@if(SCREEN_SPACE_AMBIENT_OCCLUSION) {
538 let ssao_tex_pos = vec2<i32>(in.position.xy - view.viewport.xy);
539 let ssao = textureLoad(screen_space_ambient_occlusion_texture, ssao_tex_pos, 0i).r;
540 let ssao_multibounce = ssao_multibounce(ssao, pbr_input.material.base_color.rgb);
541 diffuse_occlusion = min(diffuse_occlusion, ssao_multibounce);
542 // Use SSAO to estimate the specular occlusion.
543 // Lagarde and Rousiers 2014, "Moving Frostbite to Physically Based Rendering"
544 let roughness = lighting::perceptualRoughnessToRoughness(pbr_input.material.perceptual_roughness);
545 specular_occlusion = saturate(pow(NdotV + ssao, exp2(-16.0 * roughness - 1.0)) - 1.0 + ssao);
547 pbr_input.diffuse_occlusion = diffuse_occlusion;
548 pbr_input.specular_occlusion = specular_occlusion;
550 // N (normal vector)
551@if(!LOAD_PREPASS_NORMALS) {
553 pbr_input.N = normalize(pbr_input.world_normal);
554 pbr_input.clearcoat_N = pbr_input.N;
556@if(VERTEX_UVS && VERTEX_TANGENTS)
557 let TBN = pbr_functions::calculate_tbn_mikktspace(pbr_input.world_normal, in.world_tangent);
559@if(VERTEX_UVS && VERTEX_TANGENTS && STANDARD_MATERIAL_NORMAL_MAP) {
561 @if(BINDLESS)
562 let texture = bindless_textures_2d[material_indices[slot].normal_map_texture];
563 @else
564 let texture = pbr_bindings::normal_map_texture;
565 @if(BINDLESS)
566 let sampler_ = bindless_samplers_filtering[material_indices[slot].normal_map_sampler];
567 @else
568 let sampler_ = pbr_bindings::normal_map_sampler;
569 @if(STANDARD_MATERIAL_NORMAL_MAP_UV_B)
570 let coords = uv_b;
571 @else
572 let coords = uv;
573 @if(MESHLET_MESH_MATERIAL_PASS)
574 let Nt = textureSampleGrad(texture, sampler_, coords, bias.ddx_uv, bias.ddy_uv).rgb;
575 @else
576 let Nt = textureSampleBias(texture, sampler_, coords, bias.mip_bias).rgb;
578 pbr_input.N = pbr_functions::apply_normal_mapping(
579 flags,
580 TBN,
581 double_sided,
582 is_logically_front,
583 Nt,
584 );
588@if(VERTEX_UVS && VERTEX_TANGENTS && STANDARD_MATERIAL_CLEARCOAT) {
590 // Note: `KHR_materials_clearcoat` specifies that, if there's no
591 // clearcoat normal map, we must set the normal to the mesh's normal,
592 // and not to the main layer's bumped normal.
594@if(STANDARD_MATERIAL_CLEARCOAT_NORMAL_MAP) {
596 @if(BINDLESS)
597 let clearcoat_texture = bindless_textures_2d[material_indices[slot].clearcoat_normal_texture];
598 @else
599 let clearcoat_texture = pbr_bindings::clearcoat_normal_texture;
600 @if(BINDLESS)
601 let clearcoat_sampler = bindless_samplers_filtering[material_indices[slot].clearcoat_normal_sampler];
602 @else
603 let clearcoat_sampler = pbr_bindings::clearcoat_normal_sampler;
604 @if(STANDARD_MATERIAL_CLEARCOAT_NORMAL_UV_B)
605 let clearcoat_coords = uv_b;
606 @else
607 let clearcoat_coords = uv;
608 @if(MESHLET_MESH_MATERIAL_PASS)
609 let clearcoat_Nt = textureSampleGrad(clearcoat_texture, clearcoat_sampler, clearcoat_coords, bias.ddx_uv, bias.ddy_uv).rgb;
610 @else
611 let clearcoat_Nt = textureSampleBias(clearcoat_texture, clearcoat_sampler, clearcoat_coords, bias.mip_bias).rgb;
613 pbr_input.clearcoat_N = pbr_functions::apply_normal_mapping(
614 flags,
615 TBN,
616 double_sided,
617 is_logically_front,
618 clearcoat_Nt,
619 );
625 // Take anisotropy into account.
626 //
627 // This code comes from the `KHR_materials_anisotropy` spec:
628 // <https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_materials_anisotropy/README.md#individual-lights>
629@if(PBR_ANISOTROPY_TEXTURE_SUPPORTED && VERTEX_TANGENTS && STANDARD_MATERIAL_ANISOTROPY) {
631@if(BINDLESS)
632 var anisotropy_strength =
633 pbr_bindings::material_array[material_indices[slot].material].anisotropy_strength;
634@else
635 var anisotropy_strength = pbr_bindings::material.anisotropy_strength;
636@if(BINDLESS)
637 var anisotropy_direction =
638 pbr_bindings::material_array[material_indices[slot].material].anisotropy_rotation;
639@else
640 var anisotropy_direction = pbr_bindings::material.anisotropy_rotation;
642 // Adjust based on the anisotropy map if there is one.
643 if ((flags & pbr_types::STANDARD_MATERIAL_FLAGS_ANISOTROPY_TEXTURE_BIT) != 0u) {
644 @if(BINDLESS)
645 let texture = bindless_textures_2d[material_indices[slot].anisotropy_texture];
646 @else
647 let texture = pbr_bindings::anisotropy_texture;
648 @if(BINDLESS)
649 let sampler_ = bindless_samplers_filtering[material_indices[slot].anisotropy_sampler];
650 @else
651 let sampler_ = pbr_bindings::anisotropy_sampler;
652 @if(STANDARD_MATERIAL_ANISOTROPY_UV_B)
653 let coords = uv_b;
654 @else
655 let coords = uv;
656 @if(MESHLET_MESH_MATERIAL_PASS)
657 let anisotropy_texel = textureSampleGrad(texture, sampler_, coords, bias.ddx_uv, bias.ddy_uv).rgb;
658 @else
659 let anisotropy_texel = textureSampleBias(texture, sampler_, coords, bias.mip_bias).rgb;
661 let anisotropy_direction_from_texture = normalize(anisotropy_texel.rg * 2.0 - 1.0);
662 // Rotate by the anisotropy direction.
663 anisotropy_direction =
664 mat2x2(anisotropy_direction.xy, anisotropy_direction.yx * vec2(-1.0, 1.0)) *
665 anisotropy_direction_from_texture;
666 anisotropy_strength *= anisotropy_texel.b;
667 }
669 pbr_input.anisotropy_strength = anisotropy_strength;
671 let anisotropy_T = normalize(TBN * vec3(anisotropy_direction, 0.0));
672 let anisotropy_B = normalize(cross(pbr_input.world_normal, anisotropy_T));
673 pbr_input.anisotropy_T = anisotropy_T;
674 pbr_input.anisotropy_B = anisotropy_B;
680// TODO: Meshlet support
681@if(LIGHTMAP) {
683@if(BINDLESS)
684 let lightmap_exposure =
685 pbr_bindings::material_array[material_indices[slot].material].lightmap_exposure;
686@else
687 let lightmap_exposure = pbr_bindings::material.lightmap_exposure;
689 pbr_input.lightmap_light = lightmap(in.uv_b, lightmap_exposure, in.instance_index);
691 }
693 return pbr_input;
Contents