16#import bevy_core_pipeline::fullscreen_vertex_shader::FullscreenVertexOutput 17#import bevy_pbr::atmosphere::{ 18 functions::{calculate_visible_sun_ratio, clamp_to_surface}, 19 bruneton_functions::transmittance_lut_r_mu_to_uv, 21#import bevy_pbr::mesh_functions::{get_world_from_local, mesh_position_local_to_clip} 22#import bevy_pbr::mesh_view_bindings::{ 23 globals, lights, view, clustered_lights, 24 atmosphere, atmosphere_transmittance_texture, atmosphere_transmittance_sampler 26#import bevy_pbr::mesh_view_types::{ 27 DIRECTIONAL_LIGHT_FLAGS_VOLUMETRIC_BIT, 28 POINT_LIGHT_FLAGS_SHADOWS_ENABLED_BIT, 29 POINT_LIGHT_FLAGS_VOLUMETRIC_BIT, 30 POINT_LIGHT_FLAGS_SPOT_LIGHT_Y_NEGATIVE, 32#import bevy_pbr::shadow_sampling::{ 33 sample_shadow_map_hardware, 34 sample_shadow_cubemap, 36 SPOT_SHADOW_TEXEL_SIZE 38#import bevy_pbr::shadows::{get_cascade_index, world_to_directional_light_local} 39#import bevy_pbr::utils::interleaved_gradient_noise 40#import bevy_pbr::view_transformations::{ 44 position_ndc_to_world, 45 position_view_to_world 47#import bevy_pbr::clustered_forward as clustering 48#import bevy_pbr::lighting::getDistanceAttenuation; 53 clip_from_local: mat4x4<f32>, 54 uvw_from_world: mat4x4<f32>, 55 far_planes: array<vec4<f32>, 3>, 57 light_tint: vec3<f32>, 58 ambient_color: vec3<f32>, 59 ambient_intensity: f32, 65 density_texture_offset: vec3<f32>, 66 scattering_asymmetry: f32, 71@group(1) @binding(0) var<uniform> volumetric_fog: VolumetricFog; 74@group(1) @binding(1) var depth_texture: texture_depth_multisampled_2d; 76@group(1) @binding(1) var depth_texture: texture_depth_2d; 80@group(1) @binding(2) var density_texture: texture_3d<f32>; 81@group(1) @binding(3) var density_sampler: sampler; 82#endif // DENSITY_TEXTURE 85const FRAC_4_PI: f32 = 0.07957747154594767; 88 @builtin(instance_index) instance_index: u32, 89 @location(0) position: vec3<f32>, 93fn vertex(vertex: Vertex) -> @builtin(position) vec4<f32> { 94 return volumetric_fog.clip_from_local * vec4<f32>(vertex.position, 1.0); 106fn henyey_greenstein(neg_LdotV: f32) -> f32 { 107 let g = volumetric_fog.scattering_asymmetry; 108 let denom = 1.0 + g * g - 2.0 * g * neg_LdotV; 109 return FRAC_4_PI * (1.0 - g * g) / (denom * sqrt(denom)); 113fn fragment(@builtin(position) position: vec4<f32>) -> @location(0) vec4<f32> { 115 let uvw_from_world = volumetric_fog.uvw_from_world; 116 let fog_color = volumetric_fog.fog_color; 117 let ambient_color = volumetric_fog.ambient_color; 118 let ambient_intensity = volumetric_fog.ambient_intensity; 119 let step_count = volumetric_fog.step_count; 120 let bounding_radius = volumetric_fog.bounding_radius; 121 let absorption = volumetric_fog.absorption; 122 let scattering = volumetric_fog.scattering; 123 let density_factor = volumetric_fog.density_factor; 124 let density_texture_offset = volumetric_fog.density_texture_offset; 125 let light_tint = volumetric_fog.light_tint; 126 let light_intensity = volumetric_fog.light_intensity; 127 let jitter_strength = volumetric_fog.jitter_strength; 130 let exposure = view.exposure; 135 let frag_coord = position; 136 let ndc_end_depth_from_buffer = textureLoad(depth_texture, vec2<i32>(frag_coord.xy), 0); 137 let view_end_depth_from_buffer = -position_ndc_to_view( 138 frag_coord_to_ndc(vec4(position.xy, ndc_end_depth_from_buffer, 1.0))).z; 142 let view_start_pos = position_ndc_to_view(frag_coord_to_ndc(frag_coord)); 146 var end_depth_view = 0.0; 147 for (var plane_index = 0; plane_index < 3; plane_index += 1) { 148 let plane = volumetric_fog.far_planes[plane_index]; 149 let other_plane_a = volumetric_fog.far_planes[(plane_index + 1) % 3]; 150 let other_plane_b = volumetric_fog.far_planes[(plane_index + 2) % 3]; 154 let t = -plane.w / dot(plane.xyz, view_start_pos.xyz); 158 let hit_pos = view_start_pos.xyz * t; 161 let other_sides = vec2( 162 dot(vec4(hit_pos, 1.0), other_plane_a) >= 0.0, 163 dot(vec4(hit_pos, 1.0), other_plane_b) >= 0.0 167 if (all(other_sides)) { 168 end_depth_view = -hit_pos.z; 175 end_depth_view = min(end_depth_view, view_end_depth_from_buffer); 178 let start_depth_view = -depth_ndc_to_view_z(frag_coord.z); 180 let ray_length_view = max(0.0, end_depth_view - start_depth_view); 183 if (ray_length_view == 0.0) { 184 return vec4(0.0, 0.0, 0.0, 0.0); 186 let inv_step_count = 1.0 / f32(step_count); 187 let step_size_world = ray_length_view * inv_step_count; 189 let directional_light_count = lights.n_directional_lights; 193 let Rd_ndc = vec3(frag_coord_to_ndc(position).xy, 1.0); 194 let Rd_view = normalize(position_ndc_to_view(Rd_ndc)); 195 var Ro_world = position_view_to_world(view_start_pos.xyz); 196 let Rd_world = normalize(position_ndc_to_world(Rd_ndc) - view.world_position); 199 let jitter = interleaved_gradient_noise(position.xy, globals.frame_count) * jitter_strength; 200 Ro_world += Rd_world * jitter; 212 var accumulated_color = exp(-ray_length_view * (absorption + scattering)) * ambient_color * 218 var background_alpha = 1.0; 221#ifdef DENSITY_TEXTURE 222 let Ro_uvw = (uvw_from_world * vec4(Ro_world, 1.0)).xyz; 223 let Rd_step_uvw = mat3x3(uvw_from_world[0].xyz, uvw_from_world[1].xyz, uvw_from_world[2].xyz) * 224 (Rd_world * step_size_world); 225#endif // DENSITY_TEXTURE 227 for (var light_index = 0u; light_index < directional_light_count; light_index += 1u) { 230 let light = &lights.directional_lights[light_index]; 231 if (((*light).flags & DIRECTIONAL_LIGHT_FLAGS_VOLUMETRIC_BIT) == 0) { 235 let L = (*light).direction_to_light.xyz; 238 let depth_offset = (*light).shadow_depth_bias * L; 242 let neg_LdotV = dot(normalize(L), Rd_world); 243 let phase = henyey_greenstein(neg_LdotV); 246 background_alpha = 1.0; 249 for (var step = 0u; step < step_count; step += 1u) { 251 if (background_alpha < 0.001) { 256 let P_world = Ro_world + Rd_world * f32(step) * step_size_world; 257 let P_view = view_start_pos + Rd_view * f32(step) * step_size_world; 259 var density = density_factor; 260#ifdef DENSITY_TEXTURE 266 let P_uvw = Ro_uvw + Rd_step_uvw * f32(step); 267 if (all(P_uvw >= vec3(0.0)) && all(P_uvw <= vec3(1.0))) { 268 density *= textureSampleLevel(density_texture, density_sampler, P_uvw + density_texture_offset, 0.0).r; 272#endif // DENSITY_TEXTURE 276 let sample_attenuation = exp(-step_size_world * density * (absorption + scattering)); 279 background_alpha *= sample_attenuation; 286 let cascade_index = get_cascade_index(light_index, P_view.z); 287 let light_local = world_to_directional_light_local( 290 vec4(P_world + depth_offset, 1.0) 295 var local_light_attenuation = f32(light_local.w != 0.0); 299 if (local_light_attenuation != 0.0) { 300 let cascade = &(*light).cascades[cascade_index]; 301 let array_index = i32((*light).depth_texture_base_index + cascade_index); 302 local_light_attenuation = 303 sample_shadow_map_hardware(light_local.xy, light_local.z, array_index); 306 if (local_light_attenuation != 0.0) { 307 let light_attenuation = exp(-density * bounding_radius * (absorption + scattering)); 308 var light_factors_per_step = fog_color * light_tint * light_attenuation * 309 scattering * density * step_size_world * light_intensity * exposure; 313 let P = P_world + depth_offset; 314 let P_as = (atmosphere.world_to_atmosphere * vec4(P, 1.0)).xyz; 315 let P_clamped = clamp_to_surface(atmosphere, P_as); 316 let r = length(P_clamped); 317 let local_up = normalize(P_clamped); 318 let mu_light = dot(L, local_up); 320 let transmittance = sample_transmittance_lut(r, mu_light); 321 let sun_visibility = calculate_visible_sun_ratio(atmosphere, r, mu_light, (*light).sun_disk_angular_size); 322 light_factors_per_step *= transmittance * sun_visibility; 327 let light_color_per_step = (*light).color.rgb * phase * light_factors_per_step; 330 accumulated_color += light_color_per_step * local_light_attenuation * 337 let is_orthographic = view.clip_from_view[3].w == 1.0; 340 background_alpha = 1.0; 343 for (var step = 0u; step < step_count; step += 1u) { 345 if (background_alpha < 0.001) { 350 let P_world = Ro_world + Rd_world * f32(step) * step_size_world; 351 let P_view = view_start_pos + Rd_view * f32(step) * step_size_world; 353 var density = density_factor; 354#ifdef DENSITY_TEXTURE 360 let P_uvw = Ro_uvw + Rd_step_uvw * f32(step); 361 if (all(P_uvw >= vec3(0.0)) && all(P_uvw <= vec3(1.0))) { 362 density *= textureSampleLevel(density_texture, density_sampler, P_uvw + density_texture_offset, 0.0).r; 366#endif // DENSITY_TEXTURE 368 var sample_color = vec3(0.0); 370 let cluster_index = clustering::view_fragment_cluster_index(frag_coord.xy, P_view.z, is_orthographic); 371 var clusterable_object_index_ranges = clustering::unpack_clusterable_object_index_ranges(cluster_index); 372 for (var i: u32 = clusterable_object_index_ranges.first_point_light_index_offset; 373 i < clusterable_object_index_ranges.first_reflection_probe_index_offset; 376 let light_id = clustering::get_clusterable_object_id(i); 377 let light = &clustered_lights.data[light_id]; 378 if (((*light).flags & POINT_LIGHT_FLAGS_VOLUMETRIC_BIT) == 0) { 382 let light_to_frag = (*light).position_radius.xyz - P_world; 384 let L = normalize(light_to_frag); 385 let distance_square = dot(light_to_frag, light_to_frag); 386 let distance_atten = getDistanceAttenuation(distance_square, (*light).color_inverse_square_range.w); 387 var local_light_attenuation = distance_atten; 388 if (i < clusterable_object_index_ranges.first_spot_light_index_offset) { 389 var shadow: f32 = 1.0; 390 if (((*light).flags & POINT_LIGHT_FLAGS_SHADOWS_ENABLED_BIT) != 0u) { 391 shadow = fetch_point_shadow_without_normal(light_id, vec4(P_world, 1.0), position.xy); 393 local_light_attenuation *= shadow; 397 var spot_dir = vec3<f32>((*light).light_custom_data.x, 0.0, (*light).light_custom_data.y); 398 spot_dir.y = sqrt(max(0.0, 1.0 - spot_dir.x * spot_dir.x - spot_dir.z * spot_dir.z)); 399 if ((*light).flags & POINT_LIGHT_FLAGS_SPOT_LIGHT_Y_NEGATIVE) != 0u { 400 spot_dir.y = -spot_dir.y; 406 let cd = dot(-spot_dir, normalize(light_to_frag)); 407 let attenuation = saturate(cd * (*light).light_custom_data.z + (*light).light_custom_data.w); 408 let spot_attenuation = attenuation * attenuation; 410 var shadow: f32 = 1.0; 411 if (((*light).flags & POINT_LIGHT_FLAGS_SHADOWS_ENABLED_BIT) != 0u) { 412 shadow = fetch_spot_shadow_without_normal(light_id, vec4(P_world, 1.0), position.xy); 414 local_light_attenuation *= spot_attenuation * shadow; 417 let light_attenuation = exp(-density * bounding_radius * (absorption + scattering)); 418 let light_factors_per_step = fog_color * light_tint * light_attenuation * 419 scattering * density * step_size_world * light_intensity * exposure; 423 let light_color_per_step = (*light).color_inverse_square_range.rgb * light_factors_per_step; 426 sample_color += light_color_per_step * local_light_attenuation; 431 let sample_attenuation = exp(-step_size_world * density * (absorption + scattering)); 434 background_alpha *= sample_attenuation; 435 accumulated_color += sample_color * background_alpha; 440 return vec4(accumulated_color, 1.0 - background_alpha); 443fn fetch_point_shadow_without_normal(light_id: u32, frag_position: vec4<f32>, frag_coord_xy: vec2<f32>) -> f32 { 444 let light = &clustered_lights.data[light_id]; 448 let surface_to_light = (*light).position_radius.xyz - frag_position.xyz; 449 let surface_to_light_abs = abs(surface_to_light); 450 let distance_to_light = max(surface_to_light_abs.x, max(surface_to_light_abs.y, surface_to_light_abs.z)); 455 let depth_offset = (*light).shadow_depth_bias * normalize(surface_to_light.xyz); 456 let offset_position = frag_position.xyz + depth_offset; 459 let frag_ls = offset_position.xyz - (*light).position_radius.xyz; 460 let abs_position_ls = abs(frag_ls); 461 let major_axis_magnitude = max(abs_position_ls.x, max(abs_position_ls.y, abs_position_ls.z)); 467 let zw = -major_axis_magnitude * (*light).light_custom_data.xy + (*light).light_custom_data.zw; 468 let depth = zw.x / zw.y; 472 let flip_z = vec3(1.0, 1.0, -1.0); 473 return sample_shadow_cubemap(frag_ls * flip_z, distance_to_light, depth, light_id, frag_coord_xy); 476fn fetch_spot_shadow_without_normal(light_id: u32, frag_position: vec4<f32>, frag_coord_xy: vec2<f32>) -> f32 { 477 let light = &clustered_lights.data[light_id]; 479 let surface_to_light = (*light).position_radius.xyz - frag_position.xyz; 482 var spot_dir = vec3<f32>((*light).light_custom_data.x, 0.0, (*light).light_custom_data.y); 484 spot_dir.y = sqrt(max(0.0, 1.0 - spot_dir.x * spot_dir.x - spot_dir.z * spot_dir.z)); 485 if (((*light).flags & POINT_LIGHT_FLAGS_SPOT_LIGHT_Y_NEGATIVE) != 0u) { 486 spot_dir.y = -spot_dir.y; 491 let offset_position = 493 + ((*light).shadow_depth_bias * normalize(surface_to_light)); 501 let a = -1.0 / (fwd.z + sign); 502 let b = fwd.x * fwd.y * a; 503 let up_dir = vec3<f32>(1.0 + sign * fwd.x * fwd.x * a, sign * b, -sign * fwd.x); 504 let right_dir = vec3<f32>(-b, -sign - fwd.y * fwd.y * a, fwd.y); 505 let light_inv_rot = mat3x3<f32>(right_dir, up_dir, fwd); 510 let projected_position = offset_position * light_inv_rot; 514 let f_div_minus_z = 1.0 / ((*light).spot_light_tan_angle * -projected_position.z); 515 let shadow_xy_ndc = projected_position.xy * f_div_minus_z; 517 let shadow_uv = shadow_xy_ndc * vec2<f32>(0.5, -0.5) + vec2<f32>(0.5, 0.5); 520 let depth = 0.1 / -projected_position.z; 522 return sample_shadow_map( 525 i32(light_id) + lights.spot_light_shadowmap_offset, 527 SPOT_SHADOW_TEXEL_SIZE 532fn sample_transmittance_lut(r: f32, mu: f32) -> vec3<f32> { 533 let uv = transmittance_lut_r_mu_to_uv(atmosphere, r, mu); 534 return textureSampleLevel( 535 atmosphere_transmittance_texture, 536 atmosphere_transmittance_sampler, uv, 0.0).rgb;