1#define_import_path bevy_pbr::environment_map 3#import bevy_pbr::light_probe::query_light_probe 4#import bevy_pbr::mesh_view_bindings as bindings 5#import bevy_pbr::mesh_view_bindings::light_probes 6#import bevy_pbr::mesh_view_bindings::environment_map_uniform 7#import bevy_pbr::lighting::{F_Schlick_vec, LightingInput, LayerLightingInput, LAYER_BASE, LAYER_CLEARCOAT} 8#import bevy_pbr::clustered_forward::ClusterableObjectIndexRanges 10struct EnvironmentMapLight { 15struct EnvironmentMapRadiances { 16 irradiance: vec3<f32>, 24#ifdef MULTIPLE_LIGHT_PROBES_IN_ARRAY 27 input: LayerLightingInput, 28 clusterable_object_index_ranges: ptr<function, ClusterableObjectIndexRanges>, 29 world_position: vec3<f32>, 30 found_diffuse_indirect: bool, 31) -> EnvironmentMapRadiances { 35 let NdotV = input.NdotV; 36 let perceptual_roughness = input.perceptual_roughness; 37 let roughness = input.roughness; 39 var radiances: EnvironmentMapRadiances; 42 var query_result = query_light_probe( 45 clusterable_object_index_ranges, 49 if (query_result.texture_index < 0) { 50 query_result.texture_index = light_probes.view_cubemap_index; 51 query_result.intensity = light_probes.intensity_for_view; 52 query_result.affects_lightmapped_mesh_diffuse = 53 light_probes.view_environment_map_affects_lightmapped_mesh_diffuse != 0u; 57 if (query_result.texture_index < 0) { 58 radiances.irradiance = vec3(0.0); 59 radiances.radiance = vec3(0.0); 64 let radiance_level = perceptual_roughness * f32(textureNumLevels( 65 bindings::specular_environment_maps[query_result.texture_index]) - 1u); 69 var enable_diffuse = !found_diffuse_indirect; 71 enable_diffuse = enable_diffuse && query_result.affects_lightmapped_mesh_diffuse; 75 var irradiance_sample_dir = N; 78 irradiance_sample_dir = (environment_map_uniform.transform * vec4(irradiance_sample_dir, 1.0)).xyz; 80 irradiance_sample_dir.z = -irradiance_sample_dir.z; 81 radiances.irradiance = textureSampleLevel( 82 bindings::diffuse_environment_maps[query_result.texture_index], 83 bindings::environment_map_sampler, 84 irradiance_sample_dir, 85 0.0).rgb * query_result.intensity; 88 var radiance_sample_dir = radiance_sample_direction(N, R, roughness); 91 radiance_sample_dir = (environment_map_uniform.transform * vec4(radiance_sample_dir, 1.0)).xyz; 93 radiance_sample_dir.z = -radiance_sample_dir.z; 94 radiances.radiance = textureSampleLevel( 95 bindings::specular_environment_maps[query_result.texture_index], 96 bindings::environment_map_sampler, 98 radiance_level).rgb * query_result.intensity; 103#else // MULTIPLE_LIGHT_PROBES_IN_ARRAY 106 input: LayerLightingInput, 107 clusterable_object_index_ranges: ptr<function, ClusterableObjectIndexRanges>, 108 world_position: vec3<f32>, 109 found_diffuse_indirect: bool, 110) -> EnvironmentMapRadiances { 114 let NdotV = input.NdotV; 115 let perceptual_roughness = input.perceptual_roughness; 116 let roughness = input.roughness; 118 var radiances: EnvironmentMapRadiances; 120 if (light_probes.view_cubemap_index < 0) { 121 radiances.irradiance = vec3(0.0); 122 radiances.radiance = vec3(0.0); 129 let radiance_level = perceptual_roughness * f32(light_probes.smallest_specular_mip_level_for_view); 131 let intensity = light_probes.intensity_for_view; 135 var enable_diffuse = !found_diffuse_indirect; 137 enable_diffuse = enable_diffuse && 138 light_probes.view_environment_map_affects_lightmapped_mesh_diffuse; 141 if (enable_diffuse) { 142 var irradiance_sample_dir = N; 145 irradiance_sample_dir = (environment_map_uniform.transform * vec4(irradiance_sample_dir, 1.0)).xyz; 147 irradiance_sample_dir.z = -irradiance_sample_dir.z; 148 radiances.irradiance = textureSampleLevel( 149 bindings::diffuse_environment_map, 150 bindings::environment_map_sampler, 151 irradiance_sample_dir, 152 0.0).rgb * intensity; 155 var radiance_sample_dir = radiance_sample_direction(N, R, roughness); 158 radiance_sample_dir = (environment_map_uniform.transform * vec4(radiance_sample_dir, 1.0)).xyz; 160 radiance_sample_dir.z = -radiance_sample_dir.z; 161 radiances.radiance = textureSampleLevel( 162 bindings::specular_environment_map, 163 bindings::environment_map_sampler, 165 radiance_level).rgb * intensity; 170#endif // MULTIPLE_LIGHT_PROBES_IN_ARRAY 172#ifdef STANDARD_MATERIAL_CLEARCOAT 176fn environment_map_light_clearcoat( 177 out: ptr<function, EnvironmentMapLight>, 178 input: ptr<function, LightingInput>, 179 clusterable_object_index_ranges: ptr<function, ClusterableObjectIndexRanges>, 180 found_diffuse_indirect: bool, 183 let world_position = (*input).P; 184 let clearcoat_NdotV = (*input).layers[LAYER_CLEARCOAT].NdotV; 185 let clearcoat_strength = (*input).clearcoat_strength; 189 let clearcoat_F0 = vec3<f32>(0.04); 190 let Fc = F_Schlick_vec(clearcoat_F0, 1.0, clearcoat_NdotV) * clearcoat_strength; 191 let inv_Fc = 1.0 - Fc; 193 let clearcoat_radiances = compute_radiances( 194 (*input).layers[LAYER_CLEARCOAT], 195 clusterable_object_index_ranges, 197 found_diffuse_indirect, 203 (*out).diffuse *= inv_Fc; 204 (*out).specular = (*out).specular * inv_Fc * inv_Fc + clearcoat_radiances.radiance * Fc; 207#endif // STANDARD_MATERIAL_CLEARCOAT 209fn environment_map_light( 210 input: ptr<function, LightingInput>, 211 clusterable_object_index_ranges: ptr<function, ClusterableObjectIndexRanges>, 212 found_diffuse_indirect: bool, 213) -> EnvironmentMapLight { 215 let roughness = (*input).layers[LAYER_BASE].roughness; 216 let diffuse_color = (*input).diffuse_color; 217 let NdotV = (*input).layers[LAYER_BASE].NdotV; 218 let F_ab = (*input).F_ab; 219 let F0 = (*input).F0_; 220 let world_position = (*input).P; 222 var out: EnvironmentMapLight; 224 let radiances = compute_radiances( 225 (*input).layers[LAYER_BASE], 226 clusterable_object_index_ranges, 228 found_diffuse_indirect, 231 if (all(radiances.irradiance == vec3(0.0)) && all(radiances.radiance == vec3(0.0))) { 232 out.diffuse = vec3(0.0); 233 out.specular = vec3(0.0); 240 let specular_occlusion = saturate(dot(F0, vec3(50.0 * 0.33))); 244 let Fr = max(vec3(1.0 - roughness), F0) - F0; 245 let kS = F0 + Fr * pow(1.0 - NdotV, 5.0); 246 let Ess = F_ab.x + F_ab.y; 247 let FssEss = kS * Ess * specular_occlusion; 249 let Favg = F0 + (1.0 - F0) / 21.0; 250 let Fms = FssEss * Favg / (1.0 - Ems * Favg); 251 let FmsEms = Fms * Ems; 252 let Edss = 1.0 - (FssEss + FmsEms); 253 let kD = diffuse_color * Edss; 255 if (!found_diffuse_indirect) { 256 out.diffuse = (FmsEms + kD) * radiances.irradiance; 258 out.diffuse = vec3(0.0); 261 out.specular = FssEss * radiances.radiance; 263#ifdef STANDARD_MATERIAL_CLEARCOAT 264 environment_map_light_clearcoat( 267 clusterable_object_index_ranges, 268 found_diffuse_indirect, 270#endif // STANDARD_MATERIAL_CLEARCOAT 277fn radiance_sample_direction(N: vec3<f32>, R: vec3<f32>, roughness: f32) -> vec3<f32> { 278 let smoothness = saturate(1.0 - roughness); 279 let lerp_factor = smoothness * (sqrt(smoothness) + roughness); 280 return mix(N, R, lerp_factor);