36 render::mesh_view_types::{POINT_LIGHT_FLAGS_SPOT_LIGHT_Y_NEGATIVE, RectLight}, 37 render::mesh_view_bindings as view_bindings, 38 atmosphere::functions::{calculate_visible_sun_ratio, clamp_to_surface}, 39 atmosphere::bruneton_functions::transmittance_lut_r_mu_to_uv, 41import bevy_render::maths::{PI, orthonormalize, quat_rotate}; 43const LAYER_BASE: u32 = 0; 44const LAYER_CLEARCOAT: u32 = 1; 48struct LayerLightingInput { 57 perceptual_roughness: f32, 65 @if(STANDARD_MATERIAL_CLEARCOAT) 66 layers: array<LayerLightingInput, 2>, 68 layers: array<LayerLightingInput, 1>, 76 diffuse_color: vec3<f32>, 82 F0_dielectric: vec3<f32>, 83 F0_metallic: vec3<f32>, 93 @if(STANDARD_MATERIAL_CLEARCOAT) 94 clearcoat_strength: f32, 98 @if(STANDARD_MATERIAL_ANISOTROPY) 102 @if(STANDARD_MATERIAL_ANISOTROPY) 106 @if(STANDARD_MATERIAL_ANISOTROPY) 111struct DerivedLightingInput { 128fn getDistanceAttenuation(distanceSquare: f32, inverseRangeSquared: f32) -> f32 { 129 return getRangeFalloff(distanceSquare, inverseRangeSquared) * 1.0 / max(distanceSquare, 0.0001); 133fn getRangeFalloff(distanceSquare: f32, inverseRangeSquared: f32) -> f32 { 134 let factor = distanceSquare * inverseRangeSquared; 135 let smoothFactor = saturate(1.0 - factor * factor); 136 return smoothFactor * smoothFactor; 146fn D_GGX(roughness: f32, NdotH: f32) -> f32 { 147 let oneMinusNdotHSquared = 1.0 - NdotH * NdotH; 148 let a = NdotH * roughness; 149 let k = roughness / (oneMinusNdotHSquared + a * a); 150 let d = k * k * (1.0 / PI); 170fn D_GGX_anisotropic(at: f32, ab: f32, NdotH: f32, TdotH: f32, BdotH: f32) -> f32 { 172 let f = vec3(ab * TdotH, at * BdotH, a2 * NdotH); 173 let w2 = a2 / dot(f, f); 174 let d = a2 * w2 * w2 * (1.0 / PI); 185fn V_SmithGGXCorrelated(roughness: f32, NdotV: f32, NdotL: f32) -> f32 { 186 let a2 = roughness * roughness; 187 let lambdaV = NdotL * sqrt((NdotV - a2 * NdotV) * NdotV + a2); 188 let lambdaL = NdotV * sqrt((NdotL - a2 * NdotL) * NdotL + a2); 189 let v = 0.5 / (lambdaV + lambdaL); 204 let GGX_V = NdotL * length(vec3(at * TdotV, ab * BdotV, NdotV)); 205 let GGX_L = NdotV * length(vec3(at * TdotL, ab * BdotL, NdotL)); 206 let v = 0.5 / (GGX_V + GGX_L); 212fn ggx_vndf_pdf(i: vec3<f32>, NdotH: f32, roughness: f32) -> f32 { 213 let ndf = D_GGX(roughness, NdotH); 216 let ai = roughness * i.xy; 217 let len2 = dot(ai, ai); 218 let t = sqrt(len2 + i.z * i.z); 221 let s = 1.0 + length(i.xy); 224 let k = (1.0 - a2) * s2 / (s2 + a2 * i.z * i.z); 225 return ndf / (2.0 * (k * i.z + t)); 229 return ndf * (t - i.z) / (2.0 * len2); 233fn sample_visible_ggx( 240 let alpha = roughness; 243 let wi_n = dot(view, n); 244 let wi_z = -n * wi_n; 245 let wi_xy = view + wi_z; 248 let wi_std = -normalize(alpha * wi_xy + wi_z); 251 let wi_std_z = dot(wi_std, n); 255 let s = 1.0 + length(wi_xy); 256 let a = clamp(alpha, 0.0, 1.0); 259 let k = (1.0 - a2) * s2 / (s2 + a2 * wi_n * wi_n); 260 let b = select(wi_std_z, k * wi_std_z, wi_n > 0.0); 263 let z = 1.0 - xi.y * (1.0 + b); 264 let sin_theta = sqrt(max(0.0, 1.0 - z * z)); 265 let phi = 2.0 * PI * xi.x - PI; 266 let x = sin_theta * cos(phi); 267 let y = sin_theta * sin(phi); 268 let c_std = vec3f(x, y, z); 271 let TBN = orthonormalize(n); 275 let wm_std = c + wi_std; 276 let wm_std_z = n * dot(n, wm_std); 277 let wm_std_xy = wm_std_z - wm_std; 280 let H = normalize(alpha * wm_std_xy + wm_std_z); 283 return reflect(-view, H); 287fn G_Smith(NdotV: f32, NdotL: f32, roughness: f32) -> f32 { 288 let k = roughness / 2.0; 289 let GGXL = NdotL / (NdotL * (1.0 - k) + k); 290 let GGXV = NdotV / (NdotV * (1.0 - k) + k); 298fn V_Kelemen(LdotH: f32) -> f32 { 299 let l_dot_h = max(LdotH, 0.0001); 300 return 0.25 / (l_dot_h * l_dot_h); 306fn F_Schlick_vec(f0: vec3<f32>, f90: f32, VdotH: f32) -> vec3<f32> { 308 return f0 + (f90 - f0) * pow(1.0 - VdotH, 5.0); 314fn F_Schlick(f0: f32, f90: f32, VdotH: f32) -> f32 { 316 return f0 + (f90 - f0) * pow(1.0 - VdotH, 5.0); 319fn fresnel(f0: vec3<f32>, LdotH: f32) -> vec3<f32> { 322 let f90 = saturate(dot(f0, vec3<f32>(50.0 * 0.33))); 323 return F_Schlick_vec(f0, f90, LdotH); 331fn specular_multiscatter( 337 specular_intensity: f32, 339 var Fr = (specular_intensity * D * V) * F; 342 Fr *= 1.0 + F0 * (1.0 / (F_ab.x + F_ab.y) - 1.0); 350fn derive_lighting_input(N: vec3<f32>, V: vec3<f32>, L: vec3<f32>) -> DerivedLightingInput { 351 var input: DerivedLightingInput; 352 var H: vec3<f32> = normalize(L + V); 354 input.NdotL = saturate(dot(N, L)); 355 input.NdotH = saturate(dot(N, H)); 356 input.LdotH = saturate(dot(L, H)); 361fn compute_specular_layer_values_for_point_light( 362 input: ptr<function, LightingInput>, 365 light_to_frag: vec3<f32>, 370 let R = (*input).layers[layer].R; 371 let a = (*input).layers[layer].roughness; 375 var LtFdotR = dot(light_to_frag, R); 388 LtFdotR = max(0.0001, LtFdotR); 390 let centerToRay = LtFdotR * R - light_to_frag; 391 let closestPoint = light_to_frag + centerToRay * saturate( 392 light_radius * inverseSqrt(dot(centerToRay, centerToRay))); 393 let LspecLengthInverse = inverseSqrt(dot(closestPoint, closestPoint)); 397 let a_prime = saturate(a + light_radius / (2.0 * distance)); 399 let L: vec3<f32> = closestPoint * LspecLengthInverse; 400 return vec4(L, a_prime); 406 input: ptr<function, LightingInput>, 407 derived_input: ptr<function, DerivedLightingInput>, 409 specular_intensity: f32, 412 let NdotV = (*input).layers[LAYER_BASE].NdotV; 413 let F0 = mix((*input).F0_dielectric, (*input).F0_metallic, (*input).metallic); 414 let NdotL = (*derived_input).NdotL; 415 let NdotH = (*derived_input).NdotH; 416 let LdotH = (*derived_input).LdotH; 419 let D = D_GGX(roughness, NdotH); 421 let V = V_SmithGGXCorrelated(roughness, NdotV, NdotL); 423 let F = fresnel(F0, LdotH); 426 let Fr = specular_multiscatter(D, V, F, F0, (*input).F_ab, specular_intensity); 435fn specular_clearcoat( 436 input: ptr<function, LightingInput>, 437 derived_input: ptr<function, DerivedLightingInput>, 438 clearcoat_strength: f32, 440 specular_intensity: f32, 443 let NdotH = (*derived_input).NdotH; 444 let LdotH = (*derived_input).LdotH; 447 let Dc = D_GGX(roughness, NdotH); 449 let Vc = V_Kelemen(LdotH); 451 let Fc = F_Schlick(0.04, 1.0, LdotH) * clearcoat_strength; 453 let Frc = (specular_intensity * Dc * Vc) * Fc; 454 return vec2(Fc, Frc); 457@if(STANDARD_MATERIAL_ANISOTROPY) 458fn specular_anisotropy( 459 input: ptr<function, LightingInput>, 460 derived_input: ptr<function, DerivedLightingInput>, 463 specular_intensity: f32, 466 let NdotV = (*input).layers[LAYER_BASE].NdotV; 468 let F0 = mix((*input).F0_dielectric, (*input).F0_metallic, (*input).metallic); 469 let anisotropy = (*input).anisotropy; 470 let Ta = (*input).Ta; 471 let Ba = (*input).Ba; 472 let H = (*derived_input).H; 473 let NdotL = (*derived_input).NdotL; 474 let NdotH = (*derived_input).NdotH; 475 let LdotH = (*derived_input).LdotH; 477 let TdotL = dot(Ta, L); 478 let BdotL = dot(Ba, L); 479 let TdotH = dot(Ta, H); 480 let BdotH = dot(Ba, H); 481 let TdotV = dot(Ta, V); 482 let BdotV = dot(Ba, V); 484 let ab = roughness * roughness; 485 let at = mix(ab, 1.0, anisotropy * anisotropy); 487 let Da = D_GGX_anisotropic(at, ab, NdotH, TdotH, BdotH); 488 let Va = V_GGX_anisotropic(at, ab, NdotL, NdotV, BdotV, TdotV, TdotL, BdotL); 489 let Fa = fresnel(F0, LdotH); 492 let Fr = specular_multiscatter(Da, Va, Fa, F0, (*input).F_ab, specular_intensity); 511 input: ptr<function, LightingInput>, 512 derived_input: ptr<function, DerivedLightingInput>, 515 let roughness = (*input).layers[LAYER_BASE].roughness; 516 let NdotV = (*input).layers[LAYER_BASE].NdotV; 517 let NdotL = (*derived_input).NdotL; 518 let LdotH = (*derived_input).LdotH; 520 let f90 = 0.5 + 2.0 * roughness * LdotH * LdotH; 521 let lightScatter = F_Schlick(1.0, f90, NdotL); 522 let viewScatter = F_Schlick(1.0, f90, NdotV); 523 return lightScatter * viewScatter * (1.0 / PI); 527fn F_AB(perceptual_roughness: f32, NdotV: f32) -> vec2<f32> { 529 return textureSampleLevel(view_bindings::dfg_lut, view_bindings::dfg_lut_sampler, vec2<f32>(NdotV, perceptual_roughness), 0.0).rg; 532 let c0 = vec4<f32>(-1.0, -0.0275, -0.572, 0.022); 533 let c1 = vec4<f32>(1.0, 0.0425, 1.04, -0.04); 534 let r = perceptual_roughness * c0 + c1; 535 let a004 = min(r.x * r.x, exp2(-9.28 * NdotV)) * r.x + r.y; 537 let f_ab_epsilon = 0.00005; 538 return max(vec2<f32>(-1.04, 1.04) * a004 + r.zw, vec2<f32>(f_ab_epsilon)); 542fn EnvBRDFApprox(F0: vec3<f32>, F_ab: vec2<f32>) -> vec3<f32> { 543 return F0 * F_ab.x + F_ab.y; 546fn perceptualRoughnessToRoughness(perceptualRoughness: f32) -> f32 { 550 let clampedPerceptualRoughness = clamp(perceptualRoughness, 0.089, 1.0); 551 return clampedPerceptualRoughness * clampedPerceptualRoughness; 555const CUBEMAP_TYPE_CROSS_VERTICAL: u32 = 0; 556const CUBEMAP_TYPE_CROSS_HORIZONTAL: u32 = 1; 557const CUBEMAP_TYPE_SEQUENCE_VERTICAL: u32 = 2; 558const CUBEMAP_TYPE_SEQUENCE_HORIZONTAL: u32 = 3; 560const X_PLUS: u32 = 0; 561const X_MINUS: u32 = 1; 562const Y_PLUS: u32 = 2; 563const Y_MINUS: u32 = 3; 564const Z_MINUS: u32 = 4; 565const Z_PLUS: u32 = 5; 567fn cubemap_uv(direction: vec3<f32>, cubemap_type: u32) -> vec2<f32> { 568 let abs_direction = abs(direction); 569 let max_axis = max(abs_direction.x, max(abs_direction.y, abs_direction.z)); 571 let face_index = select( 572 select(X_PLUS, X_MINUS, direction.x < 0.0), 574 select(Y_PLUS, Y_MINUS, direction.y < 0.0), 575 select(Z_PLUS, Z_MINUS, direction.z < 0.0), 576 max_axis != abs_direction.y 578 max_axis != abs_direction.x 581 var face_uv: vec2<f32>; 583 var corner_uv: vec2<u32> = vec2(0, 0); 584 var face_size: vec2<f32>; 587 case X_PLUS: { face_uv = vec2<f32>(direction.z, -direction.y); divisor = direction.x; } 588 case X_MINUS: { face_uv = vec2<f32>(-direction.z, -direction.y); divisor = -direction.x; } 589 case Y_PLUS: { face_uv = vec2<f32>(direction.x, -direction.z); divisor = direction.y; } 590 case Y_MINUS: { face_uv = vec2<f32>(direction.x, direction.z); divisor = -direction.y; } 591 case Z_PLUS: { face_uv = vec2<f32>(direction.x, direction.y); divisor = direction.z; } 592 case Z_MINUS: { face_uv = vec2<f32>(direction.x, -direction.y); divisor = -direction.z; } 595 face_uv = (face_uv / divisor) * 0.5 + 0.5; 597 switch cubemap_type { 598 case CUBEMAP_TYPE_CROSS_VERTICAL: { 599 face_size = vec2(1.0/3.0, 1.0/4.0); 600 corner_uv = vec2<u32>((0x111102u >> (4 * face_index)) & 0xFu, (0x132011u >> (4 * face_index)) & 0xFu); 602 case CUBEMAP_TYPE_CROSS_HORIZONTAL: { 603 face_size = vec2(1.0/4.0, 1.0/3.0); 604 corner_uv = vec2<u32>((0x131102u >> (4 * face_index)) & 0xFu, (0x112011u >> (4 * face_index)) & 0xFu); 606 case CUBEMAP_TYPE_SEQUENCE_HORIZONTAL: { 607 face_size = vec2(1.0/6.0, 1.0); 608 corner_uv.x = face_index; 610 case CUBEMAP_TYPE_SEQUENCE_VERTICAL: { 611 face_size = vec2(1.0, 1.0/6.0); 612 corner_uv.y = face_index; 617 return (vec2<f32>(corner_uv) + face_uv) * face_size; 628fn specular_fix_remap(a: f32) -> f32 { 629 let inv_a_sq = (1.0 - a) * (1.0 - a); 630 return 1.0 - inv_a_sq * inv_a_sq; 635 input: ptr<function, LightingInput>, 636 enable_diffuse: bool, 637 enable_texture: bool, 640 let diffuse_color = (*input).diffuse_color; 642 let N = (*input).layers[LAYER_BASE].N; 645 let light = &view_bindings::clustered_lights.data[light_id]; 646 let light_to_frag = (*light).position_radius.xyz - P; 647 let L = normalize(light_to_frag); 648 let distance_square = dot(light_to_frag, light_to_frag); 649 let distance = sqrt(distance_square); 650 let rangeAttenuation = getDistanceAttenuation(distance_square, (*light).color_inverse_square_range.w); 654 let a = (*input).layers[LAYER_BASE].roughness; 655 let specular_L_a_prime = compute_specular_layer_values_for_point_light( 660 (*light).position_radius.w, 663 let L_spec = specular_L_a_prime.xyz; 664 let a_prime = specular_L_a_prime.w; 665 var specular_derived_input = derive_lighting_input(N, V, L_spec); 667 let normalizationFactor = a / a_prime; 668 let specular_intensity = normalizationFactor * normalizationFactor; 670 let brdf_roughness = mix(a, a_prime, specular_fix_remap(a)); 672@if(STANDARD_MATERIAL_ANISOTROPY) 673 var specular_light = specular_anisotropy(input, &specular_derived_input, L, brdf_roughness, specular_intensity); 675 var specular_light = specular(input, &specular_derived_input, brdf_roughness, specular_intensity); 678 let light_radius = (*light).position_radius.w; 679 if light_radius > 0.0 { 680 let solid_angle = light_radius * light_radius / (distance * distance); 681 specular_light *= saturate(specular_derived_input.NdotL / max(specular_derived_input.NdotL + solid_angle, 1e-4)); 687 @if(STANDARD_MATERIAL_CLEARCOAT) 688 let clearcoat_N = (*input).layers[LAYER_CLEARCOAT].N; 689 @if(STANDARD_MATERIAL_CLEARCOAT) 690 let clearcoat_strength = (*input).clearcoat_strength; 691 @if(STANDARD_MATERIAL_CLEARCOAT) 692 let clearcoat_a = (*input).layers[LAYER_CLEARCOAT].roughness; 697 @if(STANDARD_MATERIAL_CLEARCOAT) 698 let clearcoat_specular_L_a_prime = compute_specular_layer_values_for_point_light( 703 (*light).position_radius.w, 706 @if(STANDARD_MATERIAL_CLEARCOAT) 707 let L_clearcoat_spec = clearcoat_specular_L_a_prime.xyz; 708 @if(STANDARD_MATERIAL_CLEARCOAT) 709 let clearcoat_a_prime = clearcoat_specular_L_a_prime.w; 710 @if(STANDARD_MATERIAL_CLEARCOAT) 711 var clearcoat_specular_derived_input = 712 derive_lighting_input(clearcoat_N, V, L_clearcoat_spec); 715 @if(STANDARD_MATERIAL_CLEARCOAT) 716 let clearcoat_normalizationFactor = clearcoat_a / clearcoat_a_prime; 718 @if(STANDARD_MATERIAL_CLEARCOAT) 719 let clearcoat_specular_intensity = clearcoat_normalizationFactor * clearcoat_normalizationFactor; 721 @if(STANDARD_MATERIAL_CLEARCOAT) 722 let clearcoat_brdf_roughness = mix(clearcoat_a, clearcoat_a_prime, specular_fix_remap(clearcoat_a)); 724 @if(STANDARD_MATERIAL_CLEARCOAT) 725 let Fc_Frc = specular_clearcoat( 727 &clearcoat_specular_derived_input, 729 clearcoat_brdf_roughness, 730 clearcoat_specular_intensity 732 @if(STANDARD_MATERIAL_CLEARCOAT) 733 let inv_Fc = 1.0 - Fc_Frc.r; 734 @if(STANDARD_MATERIAL_CLEARCOAT) 738 @if(STANDARD_MATERIAL_CLEARCOAT) 739 if light_radius > 0.0 { 740 let solid_angle = light_radius * light_radius / (distance * distance); 741 Frc *= saturate(clearcoat_specular_derived_input.NdotL / max(clearcoat_specular_derived_input.NdotL + solid_angle, 1e-4)); 746 var derived_input = derive_lighting_input(N, V, L); 747 var diffuse = vec3(0.0); 748 if (enable_diffuse) { 749 diffuse = diffuse_color * Fd_Burley(input, &derived_input); 765 var color_times_NdotL: vec3<f32>; 766@if(STANDARD_MATERIAL_CLEARCOAT) 770 color_times_NdotL = (diffuse * derived_input.NdotL + specular_light * specular_derived_input.NdotL * inv_Fc) * inv_Fc + Frc * clearcoat_specular_derived_input.NdotL; 772 color_times_NdotL = diffuse * derived_input.NdotL + specular_light * specular_derived_input.NdotL; 774 var texture_sample = 1f; 777 if enable_texture && (*light).decal_index != 0xFFFFFFFFu { 778 let relative_position = (view_bindings::clustered_decals.decals[(*light).decal_index].local_from_world * vec4(P, 1.0)).xyz; 779 let cubemap_type = view_bindings::clustered_decals.decals[(*light).decal_index].tag; 780 let decal_uv = cubemap_uv(relative_position, cubemap_type); 781 let image_index = view_bindings::clustered_decals.decals[(*light).decal_index].base_color_texture_index; 783 texture_sample = textureSampleLevel( 784 view_bindings::clustered_decal_textures[image_index], 785 view_bindings::clustered_decal_sampler, 791 return color_times_NdotL * (*light).color_inverse_square_range.rgb * 792 rangeAttenuation * texture_sample; 797 input: ptr<function, LightingInput>, 801 let point_light = point_light(light_id, input, enable_diffuse, false); 803 let light = &view_bindings::clustered_lights.data[light_id]; 806 var spot_dir = vec3<f32>((*light).light_custom_data.x, 0.0, (*light).light_custom_data.y); 807 spot_dir.y = sqrt(max(0.0, 1.0 - spot_dir.x * spot_dir.x - spot_dir.z * spot_dir.z)); 808 if ((*light).flags & POINT_LIGHT_FLAGS_SPOT_LIGHT_Y_NEGATIVE) != 0u { 809 spot_dir.y = -spot_dir.y; 811 let light_to_frag = (*light).position_radius.xyz - (*input).P.xyz; 816 let cd = dot(-spot_dir, normalize(light_to_frag)); 817 let attenuation = saturate(cd * (*light).light_custom_data.z + (*light).light_custom_data.w); 818 let spot_attenuation = attenuation * attenuation; 820 var texture_sample = 1f; 823 if (*light).decal_index != 0xFFFFFFFFu { 824 let local_position = (view_bindings::clustered_decals.decals[(*light).decal_index].local_from_world * 825 vec4((*input).P, 1.0)).xyz; 826 if local_position.z < 0.0 { 827 let decal_uv = (local_position.xy / (local_position.z * (*light).spot_light_tan_angle)) * vec2(-0.5, 0.5) + 0.5; 828 let image_index = view_bindings::clustered_decals.decals[(*light).decal_index].base_color_texture_index; 830 texture_sample = textureSampleLevel( 831 view_bindings::clustered_decal_textures[image_index], 832 view_bindings::clustered_decal_sampler, 839 return point_light * spot_attenuation * texture_sample; 844 input: ptr<function, LightingInput>, 848 let diffuse_color = (*input).diffuse_color; 849 let NdotV = (*input).layers[LAYER_BASE].NdotV; 850 let N = (*input).layers[LAYER_BASE].N; 852 let roughness = (*input).layers[LAYER_BASE].roughness; 854 let light = &view_bindings::lights.directional_lights[light_id]; 856 let L = (*light).direction_to_light.xyz; 857 var derived_input = derive_lighting_input(N, V, L); 859 var diffuse = vec3(0.0); 860 if (enable_diffuse) { 861 diffuse = diffuse_color * Fd_Burley(input, &derived_input); 864@if(STANDARD_MATERIAL_ANISOTROPY) 865 let specular_light = specular_anisotropy(input, &derived_input, L, roughness, 1.0); 867 let specular_light = specular(input, &derived_input, roughness, 1.0); 869 @if(STANDARD_MATERIAL_CLEARCOAT) 870 let clearcoat_N = (*input).layers[LAYER_CLEARCOAT].N; 871 @if(STANDARD_MATERIAL_CLEARCOAT) 872 let clearcoat_strength = (*input).clearcoat_strength; 873 @if(STANDARD_MATERIAL_CLEARCOAT) 874 let clearcoat_roughness = (*input).layers[LAYER_CLEARCOAT].roughness; 879 @if(STANDARD_MATERIAL_CLEARCOAT) 880 var derived_clearcoat_input = derive_lighting_input(clearcoat_N, V, L); 882 @if(STANDARD_MATERIAL_CLEARCOAT) 884 specular_clearcoat(input, &derived_clearcoat_input, clearcoat_strength, clearcoat_roughness, 1.0); 885 @if(STANDARD_MATERIAL_CLEARCOAT) 886 let inv_Fc = 1.0 - Fc_Frc.r; 887 @if(STANDARD_MATERIAL_CLEARCOAT) 890 var color: vec3<f32>; 891@if(STANDARD_MATERIAL_CLEARCOAT) 895 color = (diffuse + specular_light * inv_Fc) * inv_Fc * derived_input.NdotL + 896 Frc * derived_clearcoat_input.NdotL; 898 color = (diffuse + specular_light) * derived_input.NdotL; 900 var texture_sample = 1f; 903 if (*light).decal_index != 0xFFFFFFFFu { 904 let local_position = (view_bindings::clustered_decals.decals[(*light).decal_index].local_from_world * 905 vec4((*input).P, 1.0)).xyz; 906 let decal_uv = local_position.xy * vec2(-0.5, 0.5) + 0.5; 909 if (view_bindings::clustered_decals.decals[(*light).decal_index].tag != 0u) 910 || all(clamp(decal_uv, vec2(0.0), vec2(1.0)) == decal_uv) 912 let image_index = view_bindings::clustered_decals.decals[(*light).decal_index].base_color_texture_index; 914 texture_sample = textureSampleLevel( 915 view_bindings::clustered_decal_textures[image_index], 916 view_bindings::clustered_decal_sampler, 917 decal_uv - floor(decal_uv), 925color *= (*light).color.rgb * texture_sample; 929 let atmosphere = view_bindings::atmosphere; 931 view_bindings::atmosphere.world_to_atmosphere * vec4(P, 1.0) 933 let P_clamped = clamp_to_surface(atmosphere, P_as); 934 let r = length(P_clamped); 935 let local_up = normalize(P_clamped); 936 let mu_light = dot(L, local_up); 939 let transmittance = sample_transmittance_lut(r, mu_light); 940 let sun_visibility = calculate_visible_sun_ratio(atmosphere, r, mu_light, (*light).sun_disk_angular_size); 943 color *= transmittance * sun_visibility; 955fn ltc_integrate_edge(v1: vec3<f32>, v2: vec3<f32>) -> f32 { 958 let a = 0.8543985 + (0.4965155 + 0.0145206 * y) * y; 959 let b = 3.4175940 + (4.1616724 + y) * y; 961 let theta_sintheta = select(0.5 * inverseSqrt(max(1.0 - x * x, 1e-7)) - v, v, x > 0.0); 962 return cross(v1, v2).z * theta_sintheta; 965fn ltc_integrate_quad( 970 points: array<vec3<f32>, 4> 972 let T1 = normalize(V - N * dot(V, N)); 973 let T2 = -cross(N, T1); 975 let Minv_local = Minv * transpose(mat3x3<f32>(T1, T2, N)); 978 var L: array<vec3<f32>, 4>; 979 L[0] = Minv_local * (points[0] - P); 980 L[1] = Minv_local * (points[1] - P); 981 L[2] = Minv_local * (points[2] - P); 982 L[3] = Minv_local * (points[3] - P); 987 var clipped: array<vec3<f32>, 5>; 988 var n_clipped: i32 = 0; 990 for (var i = 0i; i < 4i; i++) { 992 let b = L[(i + 1) % 4]; 994 clipped[n_clipped] = a; 997 if ((a.z >= 0.0) != (b.z >= 0.0)) { 998 let t = a.z / (a.z - b.z); 999 clipped[n_clipped] = mix(a, b, t); 1004 if (n_clipped == 0) { 1008 for (var i = 0i; i < n_clipped; i++) { 1009 clipped[i] = normalize(clipped[i]); 1014 for (var i = 0i; i < n_clipped; i++) { 1015 sum += ltc_integrate_edge(clipped[i], clipped[(i + 1) % n_clipped]); 1024fn unpack_clustered_rect_light(light_id: u32) -> RectLight { 1025 let light = &view_bindings::clustered_lights.data[light_id]; 1026 let rotation = (*light).light_custom_data; 1028 vec4<f32>((*light).color_inverse_square_range.xyz, 1.0), 1029 (*light).position_radius.xyz, 1031 (*light).position_radius.w, 1032 quat_rotate(rotation, vec3<f32>(1.0, 0.0, 0.0)), 1034 (*light).color_inverse_square_range.w, 1035 quat_rotate(rotation, vec3<f32>(0.0, 1.0, 0.0)), 1043 light: ptr<function, RectLight>, 1044 input: ptr<function, LightingInput>, 1045 enable_diffuse: bool, 1048 let diffuse_color = (*input).diffuse_color; 1050 let N = (*input).layers[LAYER_BASE].N; 1052 let NdotV = (*input).layers[LAYER_BASE].NdotV; 1053 let perceptual_roughness = (*input).layers[LAYER_BASE].perceptual_roughness; 1055 let light_to_frag = (*light).position - P; 1056 let distance_square = dot(light_to_frag, light_to_frag); 1057 let inverse_range_squared = 1.0 / max((*light).range * (*light).range, 0.0001); 1058 let range_falloff = getRangeFalloff(distance_square, inverse_range_squared); 1060 let light_normal = cross((*light).up, (*light).right); 1061 let hw = (*light).right * (*light).width * 0.5; 1062 let hh = (*light).up * (*light).height * 0.5; 1063 var corners: array<vec3<f32>, 4>; 1064 corners[0] = (*light).position + hw - hh; 1065 corners[1] = (*light).position - hw - hh; 1066 corners[2] = (*light).position - hw + hh; 1067 corners[3] = (*light).position + hw + hh; 1070 if dot(light_normal, P - corners[0]) <= 0.0 { 1071 return vec3<f32>(0.0); 1074 let LUT_SCALE = 63.0 / 64.0; 1075 let LUT_BIAS = 0.5 / 64.0; 1076 let uv = vec2<f32>(perceptual_roughness, sqrt(1.0 - NdotV)) * LUT_SCALE + LUT_BIAS; 1077 let t1 = textureSampleLevel(view_bindings::area_light_luts, view_bindings::area_light_luts_sampler, uv, 0, 0.0); 1078 let t2 = textureSampleLevel(view_bindings::area_light_luts, view_bindings::area_light_luts_sampler, uv, 1, 0.0); 1081 let Minv = mat3x3<f32>( 1082 vec3<f32>(t1.x, 0.0, t1.y), 1083 vec3<f32>(0.0, 1.0, 0.0), 1084 vec3<f32>(t1.z, 0.0, t1.w), 1086 let spec = ltc_integrate_quad(N, V, P, Minv, corners); 1089 let identity = mat3x3<f32>( 1090 vec3<f32>(1.0, 0.0, 0.0), 1091 vec3<f32>(0.0, 1.0, 0.0), 1092 vec3<f32>(0.0, 0.0, 1.0), 1094 let diff = select(0.0, ltc_integrate_quad(N, V, P, identity, corners), enable_diffuse); 1097 let F0 = mix((*input).F0_dielectric, (*input).F0_metallic, (*input).metallic); 1098 let spec_weight = F0 * t2.x + (1.0 - F0) * t2.y; 1100@if(STANDARD_MATERIAL_CLEARCOAT) { 1101 let clearcoat_N = (*input).layers[LAYER_CLEARCOAT].N; 1102 let clearcoat_strength = (*input).clearcoat_strength; 1103 let clearcoat_perceptual_roughness = (*input).layers[LAYER_CLEARCOAT].perceptual_roughness; 1104 let clearcoat_NdotV = (*input).layers[LAYER_CLEARCOAT].NdotV; 1107 let cc_uv = vec2<f32>(clearcoat_perceptual_roughness, sqrt(1.0 - clearcoat_NdotV)) * LUT_SCALE + LUT_BIAS; 1108 let tc1 = textureSampleLevel(view_bindings::area_light_luts, view_bindings::area_light_luts_sampler, cc_uv, 0, 0.0); 1109 let tc2 = textureSampleLevel(view_bindings::area_light_luts, view_bindings::area_light_luts_sampler, cc_uv, 1, 0.0); 1110 let Minv_cc = mat3x3<f32>( 1111 vec3<f32>(tc1.x, 0.0, tc1.y), 1112 vec3<f32>(0.0, 1.0, 0.0), 1113 vec3<f32>(tc1.z, 0.0, tc1.w), 1115 let spec_cc = ltc_integrate_quad(clearcoat_N, V, P, Minv_cc, corners); 1118 let spec_weight_cc = 0.04 * tc2.x + (1.0 - 0.04) * tc2.y; 1119 let Fc = clearcoat_strength * spec_weight_cc; 1120 let inv_Fc = 1.0 - Fc; 1122 return ((spec_weight * spec * inv_Fc + diffuse_color * diff) * inv_Fc 1123 + spec_weight_cc * spec_cc * clearcoat_strength) * (*light).color.rgb * range_falloff; 1125 return (spec_weight * spec + diffuse_color * diff) * (*light).color.rgb * range_falloff; 1131fn sample_transmittance_lut(r: f32, mu: f32) -> vec3<f32> { 1132 let uv = transmittance_lut_r_mu_to_uv(view_bindings::atmosphere, r, mu); 1133 return textureSampleLevel( 1134 view_bindings::atmosphere_transmittance_texture, 1135 view_bindings::atmosphere_transmittance_sampler, uv, 0.0).rgb;