1#define_import_path bevy_pbr::transmission 6 utils::interleaved_gradient_noise, 8 mesh_view_bindings as view_bindings, 11#import bevy_render::maths::PI 13#ifdef TONEMAP_IN_SHADER 14#import bevy_core_pipeline::tonemapping::approximate_inverse_tone_mapping 17fn specular_transmissive_light(world_position: vec4<f32>, frag_coord: vec3<f32>, view_z: f32, N: vec3<f32>, V: vec3<f32>, F0: vec3<f32>, ior: f32, thickness: f32, perceptual_roughness: f32, specular_transmissive_color: vec3<f32>, transmitted_environment_light_specular: vec3<f32>) -> vec3<f32> { 23 let NdotI = dot(N, I); 26 let k = 1.0 - eta * eta * (1.0 - NdotI * NdotI); 27 let T = eta * I - (eta * NdotI + sqrt(k)) * N; 30 let exit_position = world_position.xyz + T * thickness; 33 let clip_exit_position = view_bindings::view.clip_from_world * vec4<f32>(exit_position, 1.0); 36 let subview_position = (clip_exit_position.xy / clip_exit_position.w) * vec2<f32>(0.5, -0.5) + 0.5; 37 let viewport_origin = view_bindings::view.viewport.xy; 38 let viewport_size = view_bindings::view.viewport.zw; 39 let full_size = vec2<f32>(textureDimensions(view_bindings::view_transmission_texture)); 40 let offset_position = (subview_position * viewport_size + viewport_origin) / full_size; 43 var background_color: vec4<f32>; 44 if perceptual_roughness == 0.0 { 46 background_color = fetch_transmissive_background_non_rough(offset_position, frag_coord); 48 background_color = fetch_transmissive_background(offset_position, frag_coord, view_z, perceptual_roughness); 52 background_color = vec4(background_color.rgb / view_bindings::view.exposure, background_color.a); 55 let MinusNdotT = dot(-N, T); 58 let F = vec3(1.0) - lighting::fresnel(F0, MinusNdotT); 61 return F * specular_transmissive_color * mix(transmitted_environment_light_specular, background_color.rgb, background_color.a); 64fn fetch_transmissive_background_non_rough(offset_position: vec2<f32>, frag_coord: vec3<f32>) -> vec4<f32> { 65 var background_color = textureSampleLevel( 66 view_bindings::view_transmission_texture, 67 view_bindings::view_transmission_sampler, 75 if prepass_utils::prepass_depth(vec4<f32>(offset_position * view_bindings::view.viewport.zw, 0.0, 0.0), 0u) > frag_coord.z { 76 background_color.a = 0.0; 81#ifdef TONEMAP_IN_SHADER 82 background_color = approximate_inverse_tone_mapping(background_color, view_bindings::view.color_grading); 85 return background_color; 88fn fetch_transmissive_background(offset_position: vec2<f32>, frag_coord: vec3<f32>, view_z: f32, perceptual_roughness: f32) -> vec4<f32> { 90 let aspect = view_bindings::view.viewport.z / view_bindings::view.viewport.w; 102 let blur_intensity = (perceptual_roughness * perceptual_roughness) / view_z; 104#ifdef SCREEN_SPACE_SPECULAR_TRANSMISSION_BLUR_TAPS 105 let num_taps = #{SCREEN_SPACE_SPECULAR_TRANSMISSION_BLUR_TAPS}; 109 let num_spirals = i32(ceil(f32(num_taps) / 8.0)); 110#ifdef TEMPORAL_JITTER 111 let random_angle = interleaved_gradient_noise(frag_coord.xy, view_bindings::globals.frame_count); 113 let random_angle = interleaved_gradient_noise(frag_coord.xy, 0u); 116 let pixel_checkboard = ( 117#ifdef TEMPORAL_JITTER 119 (i32(frag_coord.x) + i32(frag_coord.y) + i32(view_bindings::globals.frame_count)) % 2 125 (i32(frag_coord.x) + i32(frag_coord.y)) % 2 129 var result = vec4<f32>(0.0); 130 for (var i: i32 = 0; i < num_taps; i = i + 1) { 131 let current_spiral = (i >> 3u); 132 let angle = (random_angle + f32(current_spiral) / f32(num_spirals)) * 2.0 * PI; 133 let m = vec2(sin(angle), cos(angle)); 134 let rotation_matrix = mat2x2( 140 var spiral_offset: vec2<f32>; 147 case 0: { spiral_offset = utils::SPIRAL_OFFSET_0_; } 148 case 1: { spiral_offset = utils::SPIRAL_OFFSET_2_; } 149 case 2: { spiral_offset = utils::SPIRAL_OFFSET_4_; } 150 case 3: { spiral_offset = utils::SPIRAL_OFFSET_6_; } 151 case 4: { spiral_offset = utils::SPIRAL_OFFSET_1_; } 152 case 5: { spiral_offset = utils::SPIRAL_OFFSET_3_; } 153 case 6: { spiral_offset = utils::SPIRAL_OFFSET_5_; } 154 case 7: { spiral_offset = utils::SPIRAL_OFFSET_7_; } 159 spiral_offset *= 1.0 - (0.5 * f32(current_spiral + 1) / f32(num_spirals)); 162 let rotated_spiral_offset = (rotation_matrix * spiral_offset) * vec2(1.0, aspect); 165 let modified_offset_position = offset_position + rotated_spiral_offset * blur_intensity * (1.0 - f32(pixel_checkboard) * 0.1); 168 var sample = textureSampleLevel( 169 view_bindings::view_transmission_texture, 170 view_bindings::view_transmission_sampler, 171 modified_offset_position, 178 if prepass_utils::prepass_depth(vec4<f32>(modified_offset_position * view_bindings::view.viewport.zw, 0.0, 0.0), 0u) > frag_coord.z { 179 sample = vec4<f32>(0.0); 188 let normalized_rgb = normalize(sample.rgb); 189 result += vec4(min(sample.rgb, normalized_rgb / saturate(blur_intensity / 2.0)), sample.a); 192 result /= f32(num_taps); 194#ifdef TONEMAP_IN_SHADER 195 result = approximate_inverse_tone_mapping(result, view_bindings::view.color_grading);