3 pbr_fragment::pbr_input_from_standard_material, 4 decal::clustered::apply_decal_base_color, 5 mesh_view_bindings::{view, lights, clusterable_objects}, 7 pbr_types::{PbrInput, STANDARD_MATERIAL_FLAGS_UNLIT_BIT}, 8 forward_io::{FragmentOutput}, 12 main_pass_post_lighting_processing, 13 visibility_range_dither 15 shadows::{fetch_directional_shadow, fetch_point_shadow}, 16 mesh_view_types::POINT_LIGHT_FLAGS_SHADOWS_ENABLED_BIT, 18 fragment_cluster_index, 19 unpack_clusterable_object_index_ranges, 20 get_clusterable_object_id 24#import bevy_feronia::forward_sss_io::VertexOutput 25#import bevy_feronia::wind::Wind 28 #import bevy_feronia::bindings::{wind_indices, wind_material} 30 #import bevy_feronia::bindings::{wind} 36 @builtin(front_facing) is_front: bool, 38 var standard_in: bevy_pbr::forward_io::VertexOutput; 40 standard_in.position = in.position; 41 standard_in.world_position = in.world_position; 43 standard_in.world_normal = in.world_normal; 46 standard_in.world_normal = -standard_in.world_normal; 52 standard_in.uv = in.uv; 56 standard_in.world_tangent = in.world_tangent; 58 standard_in.instance_index = in.instance_index; 60#ifdef VISIBILITY_RANGE_DITHER 61 standard_in.visibility_range_dither = in.visibility_range_dither; 62 visibility_range_dither(in.position, in.visibility_range_dither); 65 var pbr_input = pbr_input_from_standard_material(standard_in, is_front); 67 pbr_input.material.base_color = alpha_discard(pbr_input.material, pbr_input.material.base_color); 69 var out: FragmentOutput; 72 let slot = mesh[in.instance_index].material_and_lightmap_bind_group_slot & 0xffffu; 73 let wind = wind_material[wind_indices[slot].material]; 76 if (pbr_input.material.flags & STANDARD_MATERIAL_FLAGS_UNLIT_BIT) == 0u { 77 #ifdef SUBSURFACE_SCATTERING 78 let sss_glow = calculate_sss_lighting(wind.sss_scale, wind.sss_intensity, pbr_input, in.thinness_factor); 81 out.color = vec4<f32>(sss_glow, 1.0); 84 pbr_input.material.emissive = vec4<f32>( 85 pbr_input.material.emissive.rgb + (sss_glow * pbr_input.material.base_color.rgb), 86 pbr_input.material.emissive.a 91 out.color = apply_pbr_lighting(pbr_input); 93 out.color = pbr_input.material.base_color; 96 out.color = main_pass_post_lighting_processing(pbr_input, out.color); 99 out.color = wind.debug_color; 113const SSS_DISTORTION: f32 = 0.5; 116const SSS_WRAP: f32 = 0.2; 117const SSS_WRAP_INV: f32 = 1.0 / (1.0 + SSS_WRAP); 121const LIGHT_INTENSITY_SCALE = 0.00005; 123fn calculate_sss_lighting(scale:f32, intensity:f32, pbr_input: PbrInput, thinness_factor: f32) -> vec3<f32> { 124 var sss_light = vec3<f32>(0.0); 126 let view_pos = view.view_from_world * pbr_input.world_position; 127 let view_z = view_pos.z; 128 let cluster_index = fragment_cluster_index(pbr_input.frag_coord.xy, view_z, pbr_input.is_orthographic); 129 let ranges = unpack_clusterable_object_index_ranges(cluster_index); 132 for (var i = ranges.first_point_light_index_offset; i < ranges.first_spot_light_index_offset; i = i + 1u) { 133 let light_id = get_clusterable_object_id(i); 134 let light = clusterable_objects.data[light_id]; 138 if (light.flags & POINT_LIGHT_FLAGS_SHADOWS_ENABLED_BIT)!= 0u { 139 shadow = fetch_point_shadow(light_id, pbr_input.world_position, pbr_input.world_normal); 142 if (shadow <= 0.0) { continue; } 145 let light_position = light.position_radius.xyz; 146 let scaled_light_color = light.color_inverse_square_range.rgb * LIGHT_INTENSITY_SCALE; 147 let inverse_square_range = light.color_inverse_square_range.w; 149 if (inverse_square_range <= 0.0) { continue; } 152 let range_sq = 1.0 / inverse_square_range; 153 let light_vector = light_position - pbr_input.world_position.xyz; 154 let distance_sq = dot(light_vector, light_vector); 156 if (distance_sq > range_sq) { continue; } 158 let L = normalize(light_vector); 160 let att_factor = saturate(1.0 - distance_sq / range_sq); 161 let attenuation = att_factor * att_factor; 162 let light_contribution = scaled_light_color * attenuation; 165 let H = normalize(L + pbr_input.world_normal * SSS_DISTORTION); 167 let back_scatter_dot = saturate(dot(pbr_input.V, -H)); 170 let t = back_scatter_dot * back_scatter_dot; 172 let back_scatter = t2 * t2 * scale; 174 let front_scatter = saturate((dot(pbr_input.world_normal, L) + SSS_WRAP) * SSS_WRAP_INV); 176 let sss_factor = back_scatter + front_scatter; 178 sss_light += sss_factor * light_contribution * shadow; 182 for (var i = 0u; i < lights.n_directional_lights; i = i + 1u) { 184 let shadow = fetch_directional_shadow(i, pbr_input.world_position, pbr_input.world_normal, view_z); 185 if (shadow <= 0.0) { continue; } 187 let sun = lights.directional_lights[i]; 188 let L = sun.direction_to_light; 191 let H = normalize(L + pbr_input.world_normal * SSS_DISTORTION); 192 let back_scatter_dot = saturate(dot(pbr_input.V, -H)); 195 let t = back_scatter_dot * back_scatter_dot; 197 let back_scatter = t2 * t2 * scale; 199 let front_scatter = saturate((dot(pbr_input.world_normal, L) + SSS_WRAP) * SSS_WRAP_INV); 201 let sss_factor = back_scatter + front_scatter; 202 let light_contribution = sun.color.rgb * LIGHT_INTENSITY_SCALE; 204 sss_light += sss_factor * light_contribution * shadow; 207 return sss_light * intensity * thinness_factor;