1#define_import_path bevy_pbr::atmosphere::functions 3#import bevy_render::maths::{PI, HALF_PI, PI_2, fast_acos, fast_acos_4, fast_atan2} 5#import bevy_pbr::atmosphere::{ 8 atmosphere, settings, view, lights, transmittance_lut, transmittance_lut_sampler, 9 multiscattering_lut, multiscattering_lut_sampler, sky_view_lut, sky_view_lut_sampler, 10 aerial_view_lut, aerial_view_lut_sampler, atmosphere_transforms 13 transmittance_lut_r_mu_to_uv, transmittance_lut_uv_to_r_mu, 14 ray_intersects_ground, distance_to_top_atmosphere_boundary, 15 distance_to_bottom_atmosphere_boundary 40const FRAC_PI: f32 = 0.3183098862; 41const FRAC_2_PI: f32 = 0.15915494309; 42const FRAC_3_16_PI: f32 = 0.0596831036594607509; 43const FRAC_4_PI: f32 = 0.07957747154594767; 44const ROOT_2: f32 = 1.41421356; 50const MIDPOINT_RATIO: f32 = 0.3; 54fn unit_to_sub_uvs(val: vec2<f32>, resolution: vec2<f32>) -> vec2<f32> { 55 return (val + 0.5f / resolution) * (resolution / (resolution + 1.0f)); 58fn sub_uvs_to_unit(val: vec2<f32>, resolution: vec2<f32>) -> vec2<f32> { 59 return (val - 0.5f / resolution) * (resolution / (resolution - 1.0f)); 62fn multiscattering_lut_r_mu_to_uv(r: f32, mu: f32) -> vec2<f32> { 63 let u = 0.5 + 0.5 * mu; 64 let v = saturate((r - atmosphere.bottom_radius) / (atmosphere.top_radius - atmosphere.bottom_radius)); 65 return unit_to_sub_uvs(vec2(u, v), vec2<f32>(settings.multiscattering_lut_size)); 68fn multiscattering_lut_uv_to_r_mu(uv: vec2<f32>) -> vec2<f32> { 69 let adj_uv = sub_uvs_to_unit(uv, vec2<f32>(settings.multiscattering_lut_size)); 70 let r = mix(atmosphere.bottom_radius, atmosphere.top_radius, adj_uv.y); 71 let mu = adj_uv.x * 2 - 1; 75fn sky_view_lut_r_mu_azimuth_to_uv(r: f32, mu: f32, azimuth: f32) -> vec2<f32> { 76 let u = (azimuth * FRAC_2_PI) + 0.5; 78 let v_horizon = sqrt(r * r - atmosphere.bottom_radius * atmosphere.bottom_radius); 79 let cos_beta = v_horizon / r; 82 let beta = fast_acos_4(cos_beta); 83 let horizon_zenith = PI - beta; 84 let view_zenith = fast_acos_4(mu); 89 let l = view_zenith - horizon_zenith; 92 let v = 0.5 + 0.5 * sign(l) * sqrt(abs_l / HALF_PI); 94 return unit_to_sub_uvs(vec2(u, v), vec2<f32>(settings.sky_view_lut_size)); 97fn sky_view_lut_uv_to_zenith_azimuth(r: f32, uv: vec2<f32>) -> vec2<f32> { 98 let adj_uv = sub_uvs_to_unit(vec2(uv.x, 1.0 - uv.y), vec2<f32>(settings.sky_view_lut_size)); 99 let azimuth = (adj_uv.x - 0.5) * PI_2; 102 let v_horizon = sqrt(r * r - atmosphere.bottom_radius * atmosphere.bottom_radius); 103 let cos_beta = v_horizon / r; 104 let beta = fast_acos_4(cos_beta); 105 let horizon_zenith = PI - beta; 108 let t = abs(2.0 * (adj_uv.y - 0.5)); 109 let l = sign(adj_uv.y - 0.5) * HALF_PI * t * t; 111 return vec2(horizon_zenith - l, azimuth); 116fn sample_transmittance_lut(r: f32, mu: f32) -> vec3<f32> { 117 let uv = transmittance_lut_r_mu_to_uv(r, mu); 118 return textureSampleLevel(transmittance_lut, transmittance_lut_sampler, uv, 0.0).rgb; 126fn sample_transmittance_lut_segment(r: f32, mu: f32, t: f32) -> vec3<f32> { 127 let r_t = get_local_r(r, mu, t); 128 let mu_t = clamp((r * mu + t) / r_t, -1.0, 1.0); 130 if ray_intersects_ground(r, mu) { 132 sample_transmittance_lut(r_t, -mu_t) / sample_transmittance_lut(r, -mu), 137 sample_transmittance_lut(r, mu) / sample_transmittance_lut(r_t, mu_t), vec3(1.0) 142fn sample_multiscattering_lut(r: f32, mu: f32) -> vec3<f32> { 143 let uv = multiscattering_lut_r_mu_to_uv(r, mu); 144 return textureSampleLevel(multiscattering_lut, multiscattering_lut_sampler, uv, 0.0).rgb; 147fn sample_sky_view_lut(r: f32, ray_dir_as: vec3<f32>) -> vec3<f32> { 148 let mu = ray_dir_as.y; 149 let azimuth = fast_atan2(ray_dir_as.x, -ray_dir_as.z); 150 let uv = sky_view_lut_r_mu_azimuth_to_uv(r, mu, azimuth); 151 return textureSampleLevel(sky_view_lut, sky_view_lut_sampler, uv, 0.0).rgb; 154fn ndc_to_camera_dist(ndc: vec3<f32>) -> f32 { 155 let view_pos = view.view_from_clip * vec4(ndc, 1.0); 156 let t = length(view_pos.xyz / view_pos.w) * settings.scene_units_to_m; 162fn sample_aerial_view_lut(uv: vec2<f32>, t: f32) -> vec3<f32> { 163 let t_max = settings.aerial_view_lut_max_distance; 164 let num_slices = f32(settings.aerial_view_lut_size.z); 170 let uvw = vec3(uv, saturate(t / t_max - 0.5 / num_slices)); 171 let sample = textureSampleLevel(aerial_view_lut, aerial_view_lut_sampler, uvw, 0.0); 175 let t_slice = t_max / num_slices; 176 let fade = saturate(t / t_slice); 178 return exp(sample.rgb) * fade; 188fn rayleigh(neg_LdotV: f32) -> f32 { 189 return FRAC_3_16_PI * (1 + (neg_LdotV * neg_LdotV)); 194fn henyey_greenstein(neg_LdotV: f32) -> f32 { 195 let g = atmosphere.mie_asymmetry; 196 let denom = 1.0 + g * g - 2.0 * g * neg_LdotV; 197 return FRAC_4_PI * (1.0 - g * g) / (denom * sqrt(denom)); 202struct AtmosphereSample { 204 rayleigh_scattering: vec3<f32>, 214 extinction: vec3<f32> 218fn sample_atmosphere(r: f32) -> AtmosphereSample { 219 let altitude = clamp(r, atmosphere.bottom_radius, atmosphere.top_radius) - atmosphere.bottom_radius; 222 let mie_density = exp(-atmosphere.mie_density_exp_scale * altitude); 223 let rayleigh_density = exp(-atmosphere.rayleigh_density_exp_scale * altitude); 224 var ozone_density: f32 = max(0.0, 1.0 - (abs(altitude - atmosphere.ozone_layer_altitude) / (atmosphere.ozone_layer_width * 0.5))); 226 let mie_scattering = mie_density * atmosphere.mie_scattering; 227 let mie_absorption = mie_density * atmosphere.mie_absorption; 228 let mie_extinction = mie_scattering + mie_absorption; 230 let rayleigh_scattering = rayleigh_density * atmosphere.rayleigh_scattering; 235 let ozone_absorption = ozone_density * atmosphere.ozone_absorption; 237 var sample: AtmosphereSample; 238 sample.rayleigh_scattering = rayleigh_scattering; 239 sample.mie_scattering = mie_scattering; 240 sample.extinction = rayleigh_scattering + mie_extinction + ozone_absorption; 246fn sample_local_inscattering(local_atmosphere: AtmosphereSample, ray_dir: vec3<f32>, local_r: f32, local_up: vec3<f32>) -> vec3<f32> { 247 var inscattering = vec3(0.0); 248 for (var light_i: u32 = 0u; light_i < lights.n_directional_lights; light_i++) { 249 let light = &lights.directional_lights[light_i]; 251 let mu_light = dot((*light).direction_to_light, local_up); 255 let neg_LdotV = dot((*light).direction_to_light, ray_dir); 259 let rayleigh_phase = rayleigh(neg_LdotV); 260 let mie_phase = henyey_greenstein(neg_LdotV); 261 let scattering_coeff = local_atmosphere.rayleigh_scattering * rayleigh_phase + local_atmosphere.mie_scattering * mie_phase; 263 let transmittance_to_light = sample_transmittance_lut(local_r, mu_light); 264 let shadow_factor = transmittance_to_light * f32(!ray_intersects_ground(local_r, mu_light)); 267 let scattering_factor = shadow_factor * scattering_coeff; 270 let psi_ms = sample_multiscattering_lut(local_r, mu_light); 271 let multiscattering_factor = psi_ms * (local_atmosphere.rayleigh_scattering + local_atmosphere.mie_scattering); 273 inscattering += (*light).color.rgb * (scattering_factor + multiscattering_factor); 275 return inscattering * view.exposure; 278const SUN_ANGULAR_SIZE: f32 = 0.0174533; 280fn sample_sun_radiance(ray_dir_ws: vec3<f32>) -> vec3<f32> { 281 let r = view_radius(); 282 let mu_view = ray_dir_ws.y; 283 let shadow_factor = f32(!ray_intersects_ground(r, mu_view)); 284 var sun_radiance = vec3(0.0); 285 for (var light_i: u32 = 0u; light_i < lights.n_directional_lights; light_i++) { 286 let light = &lights.directional_lights[light_i]; 287 let neg_LdotV = dot((*light).direction_to_light, ray_dir_ws); 288 let angle_to_sun = fast_acos(neg_LdotV); 289 let pixel_size = fwidth(angle_to_sun); 290 let factor = smoothstep(0.0, -pixel_size * ROOT_2, angle_to_sun - SUN_ANGULAR_SIZE * 0.5); 291 let sun_solid_angle = (SUN_ANGULAR_SIZE * SUN_ANGULAR_SIZE) * 4.0 * FRAC_PI; 292 sun_radiance += ((*light).color.rgb / sun_solid_angle) * factor * shadow_factor; 299fn max_atmosphere_distance(r: f32, mu: f32) -> f32 { 300 let t_top = distance_to_top_atmosphere_boundary(r, mu); 301 let t_bottom = distance_to_bottom_atmosphere_boundary(r, mu); 302 let hits = ray_intersects_ground(r, mu); 303 return mix(t_top, t_bottom, f32(hits)); 307fn view_radius() -> f32 { 308 return view.world_position.y * settings.scene_units_to_m + atmosphere.bottom_radius; 314fn get_local_up(r: f32, t: f32, ray_dir: vec3<f32>) -> vec3<f32> { 315 return normalize(vec3(0.0, r, 0.0) + t * ray_dir); 320fn get_local_r(r: f32, mu: f32, t: f32) -> f32 { 321 return sqrt(t * t + 2.0 * r * mu * t + r * r); 325fn uv_to_ndc(uv: vec2<f32>) -> vec2<f32> { 326 return uv * vec2(2.0, -2.0) + vec2(-1.0, 1.0); 330fn ndc_to_uv(ndc: vec2<f32>) -> vec2<f32> { 331 return ndc * vec2(0.5, -0.5) + vec2(0.5); 335fn direction_world_to_atmosphere(dir_ws: vec3<f32>) -> vec3<f32> { 336 let dir_as = atmosphere_transforms.atmosphere_from_world * vec4(dir_ws, 0.0); 341fn direction_atmosphere_to_world(dir_as: vec3<f32>) -> vec3<f32> { 342 let dir_ws = atmosphere_transforms.world_from_atmosphere * vec4(dir_as, 0.0); 348fn uv_to_ray_direction(uv: vec2<f32>) -> vec4<f32> { 357 let view_position_homogeneous = view.view_from_clip * vec4( 363 let view_ray_direction = view_position_homogeneous.xyz / view_position_homogeneous.w; 368 let ray_direction = (view.world_from_view * vec4(view_ray_direction, 0.0)).xyz; 370 return vec4(normalize(ray_direction), -view_ray_direction.z); 373fn zenith_azimuth_to_ray_dir(zenith: f32, azimuth: f32) -> vec3<f32> { 374 let sin_zenith = sin(zenith); 375 let mu = cos(zenith); 376 let sin_azimuth = sin(azimuth); 377 let cos_azimuth = cos(azimuth); 378 return vec3(sin_azimuth * sin_zenith, mu, -cos_azimuth * sin_zenith);