1#import bevy_render::maths::PI 4 utils::{sample_cosine_hemisphere, dir_to_cube_uv, sample_cube_dir, hammersley_2d, rand_vec2f} 7struct FilteringConstants { 11 noise_size_bits: vec2u, 14@group(0) @binding(0) var input_texture: texture_2d_array<f32>; 15@group(0) @binding(1) var input_sampler: sampler; 16@group(0) @binding(2) var output_texture: texture_storage_2d_array<rgba16float, write>; 17@group(0) @binding(3) var<uniform> constants: FilteringConstants; 18@group(0) @binding(4) var blue_noise_texture: texture_2d_array<f32>; 21fn sample_environment(dir: vec3f, level: f32) -> vec4f { 22 let cube_uv = dir_to_cube_uv(dir); 23 return textureSampleLevel(input_texture, input_sampler, cube_uv.uv, cube_uv.face, level); 28fn sample_noise(pixel_coords: vec2u) -> vec4f { 29 let noise_size = vec2u(1) << constants.noise_size_bits; 30 let noise_size_mask = noise_size - vec2u(1u); 31 let noise_coords = pixel_coords & noise_size_mask; 32 let uv = vec2f(noise_coords) / vec2f(noise_size); 33 return textureSampleLevel(blue_noise_texture, input_sampler, uv, 0u, 0.0); 37fn sample_noise(pixel_coords: vec2u) -> vec4f { 38 var rng_state: u32 = (pixel_coords.x * 3966231743u) ^ (pixel_coords.y * 3928936651u); 39 let rnd = rand_vec2f(&rng_state); 40 return vec4f(rnd, 0.0, 0.0); 45fn calculate_environment_map_lod(pdf: f32, width: f32, samples: f32) -> f32 { 47 let omega_s = 1.0 / (samples * pdf); 50 let omega_p = 4.0 * PI / (6.0 * width * width); 53 return 0.5 * log2(omega_s / omega_p); 57@workgroup_size(8, 8, 1) 58fn generate_radiance_map(@builtin(global_invocation_id) global_id: vec3u) { 59 let size = textureDimensions(output_texture).xy; 60 let invSize = 1.0 / vec2f(size); 62 let coords = vec2u(global_id.xy); 63 let face = global_id.z; 65 if (any(coords >= size)) { 70 let uv = (vec2f(coords) + 0.5) * invSize; 71 let normal = sample_cube_dir(uv, face); 77 let perceptual_roughness = constants.roughness; 78 let roughness = lighting::perceptualRoughnessToRoughness(perceptual_roughness); 81 let vector_noise = sample_noise(coords); 83 var radiance = vec3f(0.0); 84 var total_weight = 0.0; 87 if (roughness < 0.01) { 88 radiance = sample_environment(normal, 0.0).rgb; 89 textureStore(output_texture, coords, face, vec4f(radiance, 1.0)); 94 let sample_count = constants.sample_count; 96 for (var i = 0u; i < sample_count; i++) { 98 var xi = hammersley_2d(i, sample_count); 99 xi = fract(xi + vector_noise.rg); 102 let light_dir = lighting::sample_visible_ggx(xi, roughness, normal, view); 105 let NdotL = dot(normal, light_dir); 109 let half_vector = normalize(view + light_dir); 110 let NdotH = dot(normal, half_vector); 111 let NdotV = dot(normal, view); 114 let G = lighting::G_Smith(NdotV, NdotL, roughness); 117 let pdf = lighting::ggx_vndf_pdf(view, NdotH, roughness); 121 let width = f32(size.x); 122 let lod = calculate_environment_map_lod(pdf, width, f32(sample_count)); 125 let source_mip = max(0.0, lod); 128 var sample_color = sample_environment(light_dir, source_mip).rgb; 131 radiance += sample_color * NdotL * G; 132 total_weight += NdotL * G; 137 if (total_weight > 0.0) { 138 radiance = radiance / total_weight; 142 textureStore(output_texture, coords, face, vec4f(radiance, 1.0)); 146@workgroup_size(8, 8, 1) 147fn generate_irradiance_map(@builtin(global_invocation_id) global_id: vec3u) { 148 let size = textureDimensions(output_texture).xy; 149 let invSize = 1.0 / vec2f(size); 151 let coords = vec2u(global_id.xy); 152 let face = global_id.z; 154 if (any(coords >= size)) { 159 let uv = (vec2f(coords) + 0.5) * invSize; 160 let normal = sample_cube_dir(uv, face); 162 var irradiance = vec3f(0.0); 165 for (var i = 0u; i < constants.sample_count; i++) { 168 var rng: u32 = (coords.x * 2131358057u) ^ (coords.y * 3416869721u) ^ (face * 1199786941u) ^ (i * 566200673u); 171 var sample_dir = sample_cosine_hemisphere(normal, &rng); 174 var sample_color = sample_environment(sample_dir, 0.0).rgb; 177 irradiance += sample_color; 181 irradiance = irradiance / f32(constants.sample_count); 184 textureStore(output_texture, coords, face, vec4f(irradiance, 1.0));