1#import bevy_pbr::mesh_view_bindings::{view, lights, globals, clusterable_objects} 2#import bevy_pbr::shadows::fetch_directional_shadow 3#import bevy_pbr::shadows::fetch_point_shadow 4#import bevy_pbr::mesh_view_types::POINT_LIGHT_FLAGS_SHADOWS_ENABLED_BIT 5#import bevy_pbr::clustered_forward::{fragment_cluster_index, unpack_clusterable_object_index_ranges, get_clusterable_object_id} 7#import bevy_pbr::mesh_functions::mesh_normal_local_to_world 8#import bevy_pbr::view_transformations::position_world_to_clip 9#import bevy_pbr::utils::rand_f 10#import bevy_pbr::mesh_bindings::mesh 12#import bevy_feronia::wind::{Wind, BindlessWindIndices} 13#import bevy_feronia::types::{SampledNoise, DisplacedVertex, InstanceInfo} 14#import bevy_feronia::bindings::wind 15#import bevy_feronia::displace::displace_vertex_and_calc_normal 16#import bevy_feronia::noise::sample_noise 18struct InstanceUniforms { 19 world_from_local: mat4x4<f32>, 21 bottom_color: vec4<f32>, 22 visibility_range: vec4<f32>, 23 static_bend_strength: f32, 26 specular_strength: f32, 31var<uniform> instance_uniforms: InstanceUniforms; 34 @location(0) position: vec3<f32>, 37 @location(1) normal: vec3<f32>, 40 @location(2) uv: vec2<f32>, 43 @location(3) uv_b: vec2<f32>, 46 @location(4) tangent: vec4<f32>, 49 @location(5) color: vec4<f32>, 52 @location(6) joint_indices: vec4<u32>, 53 @location(7) joint_weights: vec4<f32>, 56 @location(8) i_pos_scale: vec4<f32>, 57 @location(9) i_index: u32, 61 @builtin(position) clip_position: vec4<f32>, 64#ifdef VISIBILITY_RANGE_DITHER 65 @location(1) @interpolate(flat) visibility_range_dither: i32, 68 @location(2) world_position: vec3<f32>, 69 @location(3) world_normal: vec3<f32>, 70 @location(4) uv: vec2<f32>, 71 @location(5) local_pos: vec3<f32>, 72 @location(6) world_tangent: vec4<f32>, 73 @location(7) curve_factor: f32, 77fn vertex(vertex: Vertex) -> VertexOutput { 78 var out: VertexOutput; 80 var scale = vertex.i_pos_scale.w; 81 var translation = vertex.i_pos_scale.xyz; 83 var world_from_local_matrix: mat4x4<f32>; 85 var rand_state = vertex.i_index; 87 world_from_local_matrix = mat4x4<f32>( 88 vec4<f32>(scale, 0.0, 0.0, 0.0), 89 vec4<f32>(0.0, scale, 0.0, 0.0), 90 vec4<f32>(0.0, 0.0, scale, 0.0), 91 vec4<f32>(translation, 1.0) 96 let angle = rand_f(&rand_state) * 6.2831853; 101 let rot_y_matrix = mat3x3<f32>( 102 vec3<f32>(c, 0.0, s), 103 vec3<f32>(0.0, 1.0, 0.0), 104 vec3<f32>(-s, 0.0, c) 107 let rot_scale_matrix = rot_y_matrix * scale; 109 world_from_local_matrix = mat4x4<f32>( 110 vec4<f32>(rot_scale_matrix[0], 0.0), 111 vec4<f32>(rot_scale_matrix[1], 0.0), 112 vec4<f32>(rot_scale_matrix[2], 0.0), 113 vec4<f32>(translation, 1.0) 118 var instance_world_matrix = instance_uniforms.world_from_local * world_from_local_matrix; 120 var instance: InstanceInfo; 121 instance.world_from_local = instance_world_matrix; 122 instance.instance_position = instance_world_matrix[3]; 123 instance.wrapped_time = globals.time; 124 instance.instance_index = vertex.i_index; 127 let raw_rand = rand_f(&rand_state); 128 let biased_rand = instance_uniforms.static_bend_strength + (raw_rand * (1. - instance_uniforms.static_bend_strength)); 130 let static_bend_angle = rand_f(&rand_state) * 6.28318; 132 let static_bend_strength = biased_rand * instance_uniforms.static_bend_strength; 134 let static_bend = vec2<f32>(cos(static_bend_angle), sin(static_bend_angle)) * static_bend_strength; 137 let noise = sample_noise(instance, vertex.position); 140 let displaced = displace_vertex_and_calc_normal( 151#ifdef VERTEX_TANGENTS 159 out.world_position = displaced.world_position.xyz; 160 out.world_normal = displaced.world_normal; 161 out.local_pos = vertex.position; 162 out.world_tangent = displaced.world_tangent; 163 out.clip_position = position_world_to_clip(out.world_position); 170 let height_range = wind.aabb_max.y - wind.aabb_min.y; 171 let normalized_height = saturate((vertex.position.y - wind.aabb_min.y) / max(height_range, 0.0001)); 174 out.ao = normalized_height; 176#ifdef VISIBILITY_RANGE_DITHER 177 out.visibility_range_dither = get_visibility_range_dither_level( 178 instance_uniforms.visibility_range, instance.world_from_local[3]); 182 out.curve_factor = instance_uniforms.curve_factor; 191#ifdef VISIBILITY_RANGE_DITHER 193fn get_visibility_range_dither_level(lod_range: vec4<f32>, world_position: vec4<f32>) -> i32 { 194 let camera_distance = length(view.world_position.xyz - world_position.xyz); 202 let offset = select(-16, 0, camera_distance >= lod_range.z); 203 let bounds = select(lod_range.xy, lod_range.zw, camera_distance >= lod_range.z); 204 let level = i32(round((camera_distance - bounds.x) / (bounds.y - bounds.x) * 16.)); 205 return offset + clamp(level, 0, 16); 215 @builtin(front_facing) is_front: bool, 216) -> @location(0) vec4<f32> { 219#ifdef VISIBILITY_RANGE_DITHER 221 bevy_pbr::pbr_functions::visibility_range_dither(in.clip_position, in.visibility_range_dither); 225 var top_color = instance_uniforms.top_color.rgb; 226 var bottom_color = instance_uniforms.bottom_color.rgb; 229 let corrected_uv = vec2<f32>(in.uv.x, 1.0 - in.uv.y); 231 let gradient_mix = pow(corrected_uv.y, 0.8); 232 let blade_color_rgb = mix(bottom_color, top_color, gradient_mix); 235 var albedo = blade_color_rgb; 238 let global_height_factor = in.ao; 241 let ambient_occlusion = mix(0.4, 1.0, global_height_factor); 243 albedo = albedo * ambient_occlusion; 245 var color_for_lighting = vec4<f32>(albedo, 1.0); 247 var normal = in.world_normal; 253#ifndef DIRECTIONAL_LIGHTS 255 return vec4<f32>(blade_color_rgb, in.ao); 263 let signed_norm_x = in.uv.x * 2.0 - 1.0; 265 let curve_angle = in.curve_factor * abs(signed_norm_x); 266 let clamped_angle = clamp(curve_angle, 0.0, 1.4); 267 let offset_mag = sin(clamped_angle); 269 let curve_offset_world = in.world_tangent.xyz * offset_mag * sign(signed_norm_x); 271 normal = normalize(normal + curve_offset_world); 289 const DIFFUSE_SCALING: f32 = 1.0; 292 const LIGHT_INTENSITY_SCALE: f32 = 0.00005; 293 const AMBIENT_INTENSITY_SCALE: f32 = 0.001; 295 var final_color_rgb = color_for_lighting.rgb * lights.ambient_color.rgb * AMBIENT_INTENSITY_SCALE; 296 var final_specular = vec3<f32>(0.); 298 let V = normalize(view.world_position.xyz - in.world_position); 300 let view_z = dot(vec4<f32>( 301 view.view_from_world[0].z, 302 view.view_from_world[1].z, 303 view.view_from_world[2].z, 304 view.view_from_world[3].z 305 ), vec4<f32>(in.world_position, 1.)); 307#ifdef DIRECTIONAL_LIGHTS 310 for (var i = 0u; i < lights.n_directional_lights; i = i + 1u) { 311 let sun = lights.directional_lights[i]; 312 let L = sun.direction_to_light; 314 let scaled_light_color = sun.color.rgb * LIGHT_INTENSITY_SCALE; 317 let NdotL_raw = dot(normal, L); 318 let NdotL_front = saturate(NdotL_raw); 319 let NdotL_back = saturate(-NdotL_raw) * instance_uniforms.translucency; 320 let NdotL = NdotL_front + NdotL_back; 323 let H = normalize(V + L); 324 let NdotH = saturate(dot(normal, H)); 325 let specular_factor = pow(NdotH, instance_uniforms.specular_power); 327 let shadow = fetch_directional_shadow( 329 vec4<f32>(in.world_position, 1.), 333 let final_shadow = clamp(shadow, 0.1, 1.); 336 final_color_rgb += color_for_lighting.rgb * scaled_light_color * NdotL * final_shadow * DIFFUSE_SCALING; 340 final_specular += scaled_light_color * specular_factor * instance_uniforms.specular_strength * shadow; 346 let is_orthographic = view.clip_from_view[3].w == 1.; 347 let cluster_index = fragment_cluster_index( 352 let ranges = unpack_clusterable_object_index_ranges(cluster_index); 354 for (var i = ranges.first_point_light_index_offset; i < ranges.first_spot_light_index_offset; i = i + 1u) { 355 let light_id = get_clusterable_object_id(i); 356 let light = clusterable_objects.data[light_id]; 358 let light_position = light.position_radius.xyz; 359 let scaled_light_color = light.color_inverse_square_range.rgb * LIGHT_INTENSITY_SCALE; 360 let inverse_square_range = light.color_inverse_square_range.w; 362 if (inverse_square_range <= 0.) { continue; } 365 let range_sq = 1. / inverse_square_range; 366 let light_vector = light_position - in.world_position.xyz; 367 let distance_sq = dot(light_vector, light_vector); 369 if (distance_sq > range_sq) { continue; } 371 let L = normalize(light_vector); 373 let range_factor = distance_sq * inverse_square_range; 374 let smooth_falloff = saturate(1.0 - range_factor); 375 let attenuation = smooth_falloff * smooth_falloff; 378 let NdotL_raw = dot(normal, L); 379 let NdotL_front = saturate(NdotL_raw); 380 let NdotL_back = saturate(-NdotL_raw) * instance_uniforms.translucency; 381 let NdotL = NdotL_front + NdotL_back; 384 let H = normalize(V + L); 385 let NdotH = saturate(dot(normal, H)); 386 let specular_factor = pow(NdotH, instance_uniforms.specular_power); 389 if ((light.flags & POINT_LIGHT_FLAGS_SHADOWS_ENABLED_BIT) != 0u) { 390 shadow = fetch_point_shadow(light_id, vec4<f32>(in.world_position, 1.), normal); 392 let final_shadow = clamp(shadow, 0.1, 1.); 395 final_color_rgb += color_for_lighting.rgb * scaled_light_color * attenuation * NdotL * final_shadow * DIFFUSE_SCALING; 399 final_specular += scaled_light_color * attenuation * specular_factor * instance_uniforms.specular_strength * shadow; 402#endif // POINT_LIGHTS 404 final_color_rgb += final_specular; 406 var final_color = vec4<f32>(final_color_rgb, in.ao); 409 final_color = wind.debug_color;