1#define_import_path bevy_pbr::lighting 4 mesh_view_types::POINT_LIGHT_FLAGS_SPOT_LIGHT_Y_NEGATIVE, 5 mesh_view_bindings as view_bindings, 7#import bevy_render::maths::PI 9const LAYER_BASE: u32 = 0; 10const LAYER_CLEARCOAT: u32 = 1; 48struct LayerLightingInput { 57 perceptual_roughness: f32, 65#ifdef STANDARD_MATERIAL_CLEARCOAT 66 layers: array<LayerLightingInput, 2>, 67#else // STANDARD_MATERIAL_CLEARCOAT 68 layers: array<LayerLightingInput, 1>, 69#endif // STANDARD_MATERIAL_CLEARCOAT 77 diffuse_color: vec3<f32>, 90#ifdef STANDARD_MATERIAL_CLEARCOAT 92 clearcoat_strength: f32, 93#endif // STANDARD_MATERIAL_CLEARCOAT 95#ifdef STANDARD_MATERIAL_ANISOTROPY 105#endif // STANDARD_MATERIAL_ANISOTROPY 109struct DerivedLightingInput { 126fn getDistanceAttenuation(distanceSquare: f32, inverseRangeSquared: f32) -> f32 { 127 let factor = distanceSquare * inverseRangeSquared; 128 let smoothFactor = saturate(1.0 - factor * factor); 129 let attenuation = smoothFactor * smoothFactor; 130 return attenuation * 1.0 / max(distanceSquare, 0.0001); 140fn D_GGX(roughness: f32, NdotH: f32) -> f32 { 141 let oneMinusNdotHSquared = 1.0 - NdotH * NdotH; 142 let a = NdotH * roughness; 143 let k = roughness / (oneMinusNdotHSquared + a * a); 144 let d = k * k * (1.0 / PI); 164fn D_GGX_anisotropic(at: f32, ab: f32, NdotH: f32, TdotH: f32, BdotH: f32) -> f32 { 166 let f = vec3(ab * TdotH, at * BdotH, a2 * NdotH); 167 let w2 = a2 / dot(f, f); 168 let d = a2 * w2 * w2 * (1.0 / PI); 179fn V_SmithGGXCorrelated(roughness: f32, NdotV: f32, NdotL: f32) -> f32 { 180 let a2 = roughness * roughness; 181 let lambdaV = NdotL * sqrt((NdotV - a2 * NdotV) * NdotV + a2); 182 let lambdaL = NdotV * sqrt((NdotL - a2 * NdotL) * NdotL + a2); 183 let v = 0.5 / (lambdaV + lambdaL); 198 let GGX_V = NdotL * length(vec3(at * TdotV, ab * BdotV, NdotV)); 199 let GGX_L = NdotV * length(vec3(at * TdotL, ab * BdotL, NdotL)); 200 let v = 0.5 / (GGX_V + GGX_L); 206fn ggx_vndf_pdf(i: vec3<f32>, NdotH: f32, roughness: f32) -> f32 { 207 let ndf = D_GGX(roughness, NdotH); 210 let ai = roughness * i.xy; 211 let len2 = dot(ai, ai); 212 let t = sqrt(len2 + i.z * i.z); 215 let s = 1.0 + length(i.xy); 218 let k = (1.0 - a2) * s2 / (s2 + a2 * i.z * i.z); 219 return ndf / (2.0 * (k * i.z + t)); 223 return ndf * (t - i.z) / (2.0 * len2); 227fn sample_visible_ggx( 234 let alpha = roughness; 237 let wi_n = dot(view, n); 238 let wi_z = -n * wi_n; 239 let wi_xy = view + wi_z; 242 let wi_std = -normalize(alpha * wi_xy + wi_z); 245 let wi_std_z = dot(wi_std, n); 249 let s = 1.0 + length(wi_xy); 250 let a = clamp(alpha, 0.0, 1.0); 253 let k = (1.0 - a2) * s2 / (s2 + a2 * wi_n * wi_n); 254 let b = select(wi_std_z, k * wi_std_z, wi_n > 0.0); 257 let z = 1.0 - xi.y * (1.0 + b); 258 let sin_theta = sqrt(max(0.0, 1.0 - z * z)); 259 let phi = 2.0 * PI * xi.x - PI; 260 let x = sin_theta * cos(phi); 261 let y = sin_theta * sin(phi); 262 let c_std = vec3f(x, y, z); 265 let up = vec3f(0.0, 0.0, 1.0); 267 let c = dot(wr, c_std) * wr / wr.z - c_std; 270 let wm_std = c + wi_std; 271 let wm_std_z = n * dot(n, wm_std); 272 let wm_std_xy = wm_std_z - wm_std; 275 let H = normalize(alpha * wm_std_xy + wm_std_z); 278 return reflect(-view, H); 282fn G_Smith(NdotV: f32, NdotL: f32, roughness: f32) -> f32 { 283 let k = roughness / 2.0; 284 let GGXL = NdotL / (NdotL * (1.0 - k) + k); 285 let GGXV = NdotV / (NdotV * (1.0 - k) + k); 293fn V_Kelemen(LdotH: f32) -> f32 { 294 return 0.25 / (LdotH * LdotH); 300fn F_Schlick_vec(f0: vec3<f32>, f90: f32, VdotH: f32) -> vec3<f32> { 302 return f0 + (f90 - f0) * pow(1.0 - VdotH, 5.0); 305fn F_Schlick(f0: f32, f90: f32, VdotH: f32) -> f32 { 307 return f0 + (f90 - f0) * pow(1.0 - VdotH, 5.0); 310fn fresnel(f0: vec3<f32>, LdotH: f32) -> vec3<f32> { 313 let f90 = saturate(dot(f0, vec3<f32>(50.0 * 0.33))); 314 return F_Schlick_vec(f0, f90, LdotH); 322fn specular_multiscatter( 328 specular_intensity: f32, 330 var Fr = (specular_intensity * D * V) * F; 331 Fr *= 1.0 + F0 * (1.0 / F_ab.x - 1.0); 339fn derive_lighting_input(N: vec3<f32>, V: vec3<f32>, L: vec3<f32>) -> DerivedLightingInput { 340 var input: DerivedLightingInput; 341 var H: vec3<f32> = normalize(L + V); 343 input.NdotL = saturate(dot(N, L)); 344 input.NdotH = saturate(dot(N, H)); 345 input.LdotH = saturate(dot(L, H)); 350fn compute_specular_layer_values_for_point_light( 351 input: ptr<function, LightingInput>, 354 light_to_frag: vec3<f32>, 355 light_position_radius: f32, 358 let R = (*input).layers[layer].R; 359 let a = (*input).layers[layer].roughness; 363 var LtFdotR = dot(light_to_frag, R); 377 LtFdotR = max(0.0001, LtFdotR); 379 let centerToRay = LtFdotR * R - light_to_frag; 380 let closestPoint = light_to_frag + centerToRay * saturate( 381 light_position_radius * inverseSqrt(dot(centerToRay, centerToRay))); 382 let LspecLengthInverse = inverseSqrt(dot(closestPoint, closestPoint)); 383 let normalizationFactor = a / saturate(a + (light_position_radius * 0.5 * LspecLengthInverse)); 384 let intensity = normalizationFactor * normalizationFactor; 386 let L: vec3<f32> = closestPoint * LspecLengthInverse; 387 return vec4(L, intensity); 393 input: ptr<function, LightingInput>, 394 derived_input: ptr<function, DerivedLightingInput>, 395 specular_intensity: f32, 398 let roughness = (*input).layers[LAYER_BASE].roughness; 399 let NdotV = (*input).layers[LAYER_BASE].NdotV; 400 let F0 = (*input).F0_; 401 let NdotL = (*derived_input).NdotL; 402 let NdotH = (*derived_input).NdotH; 403 let LdotH = (*derived_input).LdotH; 406 let D = D_GGX(roughness, NdotH); 408 let V = V_SmithGGXCorrelated(roughness, NdotV, NdotL); 410 let F = fresnel(F0, LdotH); 413 let Fr = specular_multiscatter(D, V, F, F0, (*input).F_ab, specular_intensity); 422fn specular_clearcoat( 423 input: ptr<function, LightingInput>, 424 derived_input: ptr<function, DerivedLightingInput>, 425 clearcoat_strength: f32, 426 specular_intensity: f32, 429 let roughness = (*input).layers[LAYER_CLEARCOAT].roughness; 430 let NdotH = (*derived_input).NdotH; 431 let LdotH = (*derived_input).LdotH; 434 let Dc = D_GGX(roughness, NdotH); 436 let Vc = V_Kelemen(LdotH); 438 let Fc = F_Schlick(0.04, 1.0, LdotH) * clearcoat_strength; 440 let Frc = (specular_intensity * Dc * Vc) * Fc; 441 return vec2(Fc, Frc); 444#ifdef STANDARD_MATERIAL_ANISOTROPY 446fn specular_anisotropy( 447 input: ptr<function, LightingInput>, 448 derived_input: ptr<function, DerivedLightingInput>, 450 specular_intensity: f32, 453 let roughness = (*input).layers[LAYER_BASE].roughness; 454 let NdotV = (*input).layers[LAYER_BASE].NdotV; 456 let F0 = (*input).F0_; 457 let anisotropy = (*input).anisotropy; 458 let Ta = (*input).Ta; 459 let Ba = (*input).Ba; 460 let H = (*derived_input).H; 461 let NdotL = (*derived_input).NdotL; 462 let NdotH = (*derived_input).NdotH; 463 let LdotH = (*derived_input).LdotH; 465 let TdotL = dot(Ta, L); 466 let BdotL = dot(Ba, L); 467 let TdotH = dot(Ta, H); 468 let BdotH = dot(Ba, H); 469 let TdotV = dot(Ta, V); 470 let BdotV = dot(Ba, V); 472 let ab = roughness * roughness; 473 let at = mix(ab, 1.0, anisotropy * anisotropy); 475 let Da = D_GGX_anisotropic(at, ab, NdotH, TdotH, BdotH); 476 let Va = V_GGX_anisotropic(at, ab, NdotL, NdotV, BdotV, TdotV, TdotL, BdotL); 477 let Fa = fresnel(F0, LdotH); 480 let Fr = specular_multiscatter(Da, Va, Fa, F0, (*input).F_ab, specular_intensity); 484#endif // STANDARD_MATERIAL_ANISOTROPY 501 input: ptr<function, LightingInput>, 502 derived_input: ptr<function, DerivedLightingInput>, 505 let roughness = (*input).layers[LAYER_BASE].roughness; 506 let NdotV = (*input).layers[LAYER_BASE].NdotV; 507 let NdotL = (*derived_input).NdotL; 508 let LdotH = (*derived_input).LdotH; 510 let f90 = 0.5 + 2.0 * roughness * LdotH * LdotH; 511 let lightScatter = F_Schlick(1.0, f90, NdotL); 512 let viewScatter = F_Schlick(1.0, f90, NdotV); 513 return lightScatter * viewScatter * (1.0 / PI); 519fn F_AB(perceptual_roughness: f32, NdotV: f32) -> vec2<f32> { 520 let c0 = vec4<f32>(-1.0, -0.0275, -0.572, 0.022); 521 let c1 = vec4<f32>(1.0, 0.0425, 1.04, -0.04); 522 let r = perceptual_roughness * c0 + c1; 523 let a004 = min(r.x * r.x, exp2(-9.28 * NdotV)) * r.x + r.y; 524 return vec2<f32>(-1.04, 1.04) * a004 + r.zw; 527fn EnvBRDFApprox(F0: vec3<f32>, F_ab: vec2<f32>) -> vec3<f32> { 528 return F0 * F_ab.x + F_ab.y; 531fn perceptualRoughnessToRoughness(perceptualRoughness: f32) -> f32 { 535 let clampedPerceptualRoughness = clamp(perceptualRoughness, 0.089, 1.0); 536 return clampedPerceptualRoughness * clampedPerceptualRoughness; 540const CUBEMAP_TYPE_CROSS_VERTICAL: u32 = 0; 541const CUBEMAP_TYPE_CROSS_HORIZONTAL: u32 = 1; 542const CUBEMAP_TYPE_SEQUENCE_VERTICAL: u32 = 2; 543const CUBEMAP_TYPE_SEQUENCE_HORIZONTAL: u32 = 3; 545const X_PLUS: u32 = 0; 546const X_MINUS: u32 = 1; 547const Y_PLUS: u32 = 2; 548const Y_MINUS: u32 = 3; 549const Z_MINUS: u32 = 4; 550const Z_PLUS: u32 = 5; 552fn cubemap_uv(direction: vec3<f32>, cubemap_type: u32) -> vec2<f32> { 553 let abs_direction = abs(direction); 554 let max_axis = max(abs_direction.x, max(abs_direction.y, abs_direction.z)); 556 let face_index = select( 557 select(X_PLUS, X_MINUS, direction.x < 0.0), 559 select(Y_PLUS, Y_MINUS, direction.y < 0.0), 560 select(Z_PLUS, Z_MINUS, direction.z < 0.0), 561 max_axis != abs_direction.y 563 max_axis != abs_direction.x 566 var face_uv: vec2<f32>; 568 var corner_uv: vec2<u32> = vec2(0, 0); 569 var face_size: vec2<f32>; 572 case X_PLUS: { face_uv = vec2<f32>(direction.z, -direction.y); divisor = direction.x; } 573 case X_MINUS: { face_uv = vec2<f32>(-direction.z, -direction.y); divisor = -direction.x; } 574 case Y_PLUS: { face_uv = vec2<f32>(direction.x, -direction.z); divisor = direction.y; } 575 case Y_MINUS: { face_uv = vec2<f32>(direction.x, direction.z); divisor = -direction.y; } 576 case Z_PLUS: { face_uv = vec2<f32>(direction.x, direction.y); divisor = direction.z; } 577 case Z_MINUS: { face_uv = vec2<f32>(direction.x, -direction.y); divisor = -direction.z; } 580 face_uv = (face_uv / divisor) * 0.5 + 0.5; 582 switch cubemap_type { 583 case CUBEMAP_TYPE_CROSS_VERTICAL: { 584 face_size = vec2(1.0/3.0, 1.0/4.0); 585 corner_uv = vec2<u32>((0x111102u >> (4 * face_index)) & 0xFu, (0x132011u >> (4 * face_index)) & 0xFu); 587 case CUBEMAP_TYPE_CROSS_HORIZONTAL: { 588 face_size = vec2(1.0/4.0, 1.0/3.0); 589 corner_uv = vec2<u32>((0x131102u >> (4 * face_index)) & 0xFu, (0x112011u >> (4 * face_index)) & 0xFu); 591 case CUBEMAP_TYPE_SEQUENCE_HORIZONTAL: { 592 face_size = vec2(1.0/6.0, 1.0); 593 corner_uv.x = face_index; 595 case CUBEMAP_TYPE_SEQUENCE_VERTICAL: { 596 face_size = vec2(1.0, 1.0/6.0); 597 corner_uv.y = face_index; 602 return (vec2<f32>(corner_uv) + face_uv) * face_size; 607 input: ptr<function, LightingInput>, 608 enable_diffuse: bool, 609 enable_texture: bool, 612 let diffuse_color = (*input).diffuse_color; 614 let N = (*input).layers[LAYER_BASE].N; 617 let light = &view_bindings::clusterable_objects.data[light_id]; 618 let light_to_frag = (*light).position_radius.xyz - P; 619 let L = normalize(light_to_frag); 620 let distance_square = dot(light_to_frag, light_to_frag); 621 let rangeAttenuation = getDistanceAttenuation(distance_square, (*light).color_inverse_square_range.w); 625 let specular_L_intensity = compute_specular_layer_values_for_point_light( 630 (*light).position_radius.w, 632 var specular_derived_input = derive_lighting_input(N, V, specular_L_intensity.xyz); 634 let specular_intensity = specular_L_intensity.w; 636#ifdef STANDARD_MATERIAL_ANISOTROPY 637 let specular_light = specular_anisotropy(input, &specular_derived_input, L, specular_intensity); 638#else // STANDARD_MATERIAL_ANISOTROPY 639 let specular_light = specular(input, &specular_derived_input, specular_intensity); 640#endif // STANDARD_MATERIAL_ANISOTROPY 644#ifdef STANDARD_MATERIAL_CLEARCOAT 646 let clearcoat_N = (*input).layers[LAYER_CLEARCOAT].N; 647 let clearcoat_strength = (*input).clearcoat_strength; 652 let clearcoat_specular_L_intensity = compute_specular_layer_values_for_point_light( 657 (*light).position_radius.w, 659 var clearcoat_specular_derived_input = 660 derive_lighting_input(clearcoat_N, V, clearcoat_specular_L_intensity.xyz); 663 let clearcoat_specular_intensity = clearcoat_specular_L_intensity.w; 664 let Fc_Frc = specular_clearcoat( 666 &clearcoat_specular_derived_input, 668 clearcoat_specular_intensity 670 let inv_Fc = 1.0 - Fc_Frc.r; 672#endif // STANDARD_MATERIAL_CLEARCOAT 676 var derived_input = derive_lighting_input(N, V, L); 677 var diffuse = vec3(0.0); 678 if (enable_diffuse) { 679 diffuse = diffuse_color * Fd_Burley(input, &derived_input); 695 var color: vec3<f32>; 696#ifdef STANDARD_MATERIAL_CLEARCOAT 700 color = (diffuse + specular_light * inv_Fc) * inv_Fc + Frc; 701#else // STANDARD_MATERIAL_CLEARCOAT 702 color = diffuse + specular_light; 703#endif // STANDARD_MATERIAL_CLEARCOAT 705 var texture_sample = 1f; 708 if enable_texture && (*light).decal_index != 0xFFFFFFFFu { 709 let relative_position = (view_bindings::clustered_decals.decals[(*light).decal_index].local_from_world * vec4(P, 1.0)).xyz; 710 let cubemap_type = view_bindings::clustered_decals.decals[(*light).decal_index].tag; 711 let decal_uv = cubemap_uv(relative_position, cubemap_type); 712 let image_index = view_bindings::clustered_decals.decals[(*light).decal_index].image_index; 714 texture_sample = textureSampleLevel( 715 view_bindings::clustered_decal_textures[image_index], 716 view_bindings::clustered_decal_sampler, 723 return color * (*light).color_inverse_square_range.rgb * 724 (rangeAttenuation * derived_input.NdotL) * texture_sample; 729 input: ptr<function, LightingInput>, 733 let point_light = point_light(light_id, input, enable_diffuse, false); 735 let light = &view_bindings::clusterable_objects.data[light_id]; 738 var spot_dir = vec3<f32>((*light).light_custom_data.x, 0.0, (*light).light_custom_data.y); 739 spot_dir.y = sqrt(max(0.0, 1.0 - spot_dir.x * spot_dir.x - spot_dir.z * spot_dir.z)); 740 if ((*light).flags & POINT_LIGHT_FLAGS_SPOT_LIGHT_Y_NEGATIVE) != 0u { 741 spot_dir.y = -spot_dir.y; 743 let light_to_frag = (*light).position_radius.xyz - (*input).P.xyz; 748 let cd = dot(-spot_dir, normalize(light_to_frag)); 749 let attenuation = saturate(cd * (*light).light_custom_data.z + (*light).light_custom_data.w); 750 let spot_attenuation = attenuation * attenuation; 752 var texture_sample = 1f; 755 if (*light).decal_index != 0xFFFFFFFFu { 756 let local_position = (view_bindings::clustered_decals.decals[(*light).decal_index].local_from_world * 757 vec4((*input).P, 1.0)).xyz; 758 if local_position.z < 0.0 { 759 let decal_uv = (local_position.xy / (local_position.z * (*light).spot_light_tan_angle)) * vec2(-0.5, 0.5) + 0.5; 760 let image_index = view_bindings::clustered_decals.decals[(*light).decal_index].image_index; 762 texture_sample = textureSampleLevel( 763 view_bindings::clustered_decal_textures[image_index], 764 view_bindings::clustered_decal_sampler, 772 return point_light * spot_attenuation * texture_sample; 777 input: ptr<function, LightingInput>, 781 let diffuse_color = (*input).diffuse_color; 782 let NdotV = (*input).layers[LAYER_BASE].NdotV; 783 let N = (*input).layers[LAYER_BASE].N; 785 let roughness = (*input).layers[LAYER_BASE].roughness; 787 let light = &view_bindings::lights.directional_lights[light_id]; 789 let L = (*light).direction_to_light.xyz; 790 var derived_input = derive_lighting_input(N, V, L); 792 var diffuse = vec3(0.0); 793 if (enable_diffuse) { 794 diffuse = diffuse_color * Fd_Burley(input, &derived_input); 797#ifdef STANDARD_MATERIAL_ANISOTROPY 798 let specular_light = specular_anisotropy(input, &derived_input, L, 1.0); 799#else // STANDARD_MATERIAL_ANISOTROPY 800 let specular_light = specular(input, &derived_input, 1.0); 801#endif // STANDARD_MATERIAL_ANISOTROPY 803#ifdef STANDARD_MATERIAL_CLEARCOAT 804 let clearcoat_N = (*input).layers[LAYER_CLEARCOAT].N; 805 let clearcoat_strength = (*input).clearcoat_strength; 810 var derived_clearcoat_input = derive_lighting_input(clearcoat_N, V, L); 813 specular_clearcoat(input, &derived_clearcoat_input, clearcoat_strength, 1.0); 814 let inv_Fc = 1.0 - Fc_Frc.r; 816#endif // STANDARD_MATERIAL_CLEARCOAT 818 var color: vec3<f32>; 819#ifdef STANDARD_MATERIAL_CLEARCOAT 823 color = (diffuse + specular_light * inv_Fc) * inv_Fc * derived_input.NdotL + 824 Frc * derived_clearcoat_input.NdotL; 825#else // STANDARD_MATERIAL_CLEARCOAT 826 color = (diffuse + specular_light) * derived_input.NdotL; 827#endif // STANDARD_MATERIAL_CLEARCOAT 829 var texture_sample = 1f; 832 if (*light).decal_index != 0xFFFFFFFFu { 833 let local_position = (view_bindings::clustered_decals.decals[(*light).decal_index].local_from_world * 834 vec4((*input).P, 1.0)).xyz; 835 let decal_uv = local_position.xy * vec2(-0.5, 0.5) + 0.5; 838 if (view_bindings::clustered_decals.decals[(*light).decal_index].tag != 0u) 839 || all(clamp(decal_uv, vec2(0.0), vec2(1.0)) == decal_uv) 841 let image_index = view_bindings::clustered_decals.decals[(*light).decal_index].image_index; 843 texture_sample = textureSampleLevel( 844 view_bindings::clustered_decal_textures[image_index], 845 view_bindings::clustered_decal_sampler, 846 decal_uv - floor(decal_uv), 855 return color * (*light).color.rgb * texture_sample;