8#define_import_path bevy_feronia::displace 9#import bevy_pbr::mesh_functions::{mesh_normal_local_to_world, mesh_tangent_local_to_world} 10#import bevy_pbr::mesh_view_bindings::view 11#import bevy_render::view::{position_world_to_view, position_view_to_world} 14#import bevy_feronia::types::{SampledNoise, DisplacedVertex, InstanceInfo} 15#import bevy_feronia::wind::{Wind, BindlessWindIndices} 16#import bevy_feronia::noise::sample_noise 23 local_wind_dir: vec3<f32> 26fn displace_vertex_and_calc_normal( 29 vertex_pos: vec3<f32>, 30 instance: InstanceInfo, 32 static_bend: vec2<f32>, 44 var result: DisplacedVertex; 47 let curve_data = calculate_macro_curve( 58 let final_local_pos = apply_micro_details( 66 result.world_position = instance.world_from_local * vec4<f32>(final_local_pos, 1.0); 69 result.world_position = vec4<f32>( 74 final_local_pos - vertex_pos 91 result.world_normal = mesh_normal_local_to_world(normal, instance.instance_index); 93 result.world_normal = normalize(instance.world_from_local[2].xyz); 96 #ifdef VERTEX_TANGENTS 97 result.world_tangent = mesh_tangent_local_to_world(instance.world_from_local, tangent, instance.instance_index); 99 let world_tangent_xyz = normalize(instance.world_from_local[0].xyz); 100 result.world_tangent = vec4<f32>(world_tangent_xyz, 1.0); 104#ifdef ANALYTICAL_NORMALS 117 let local_spine_direction = normalize(vec3<f32>(curve_data.slope.x, 1.0, curve_data.slope.z)); 119 let cos_twist = cos(curve_data.twist); 120 let sin_twist = sin(curve_data.twist); 122 let local_width_direction = vec3<f32>(cos_twist, 0.0, sin_twist); 123 let model_rotation_matrix = mat3x3<f32>( 124 instance.world_from_local[0].xyz, 125 instance.world_from_local[1].xyz, 126 instance.world_from_local[2].xyz 129 let world_spine = normalize(model_rotation_matrix * local_spine_direction); 130 let world_width = normalize(model_rotation_matrix * local_width_direction); 132 result.world_normal = normalize(cross(world_width, world_spine)); 133 result.world_tangent = vec4<f32>(world_width, 1.0); 143 #ifdef VERTEX_NORMALS 144 let local_normal = normal; 146 let local_normal = vec3<f32>(0.0, 0.0, 1.0); 149 #ifdef VERTEX_TANGENTS 150 let local_tangent = tangent.xyz; 151 let tangent_sign = tangent.w; 153 let local_tangent = vec3<f32>(1.0, 0.0, 0.0); 154 let tangent_sign = 1.0; 157 let local_bitangent = normalize(cross(local_normal, local_tangent) * tangent_sign); 160 let sample_offset = 0.05; 161 let base_displaced_pos = final_local_pos; 164 let neighbor_tangent_origin = vertex_pos + local_tangent * sample_offset; 165 let noise_tangent = sample_noise(instance, neighbor_tangent_origin); 166 let curve_tangent = calculate_macro_curve(neighbor_tangent_origin, wind, noise_tangent, instance, 171 let neighbor_tangent_displaced = apply_micro_details(curve_tangent.local_pos, curve_tangent, wind, instance, noise_tangent); 174 let neighbor_bitangent_origin = vertex_pos + local_bitangent * sample_offset; 175 let noise_bitangent = sample_noise(instance, neighbor_bitangent_origin); 176 let curve_bitangent = calculate_macro_curve(neighbor_bitangent_origin, wind, noise_bitangent, instance, 181 let neighbor_bitangent_displaced = apply_micro_details(curve_bitangent.local_pos, curve_bitangent, wind, instance, noise_bitangent); 184 let delta_tangent = neighbor_tangent_displaced - base_displaced_pos; 185 let delta_bitangent = neighbor_bitangent_displaced - base_displaced_pos; 187 let computed_local_normal = normalize(cross(delta_tangent, delta_bitangent) * tangent_sign); 190 let dot_alignment = dot(computed_local_normal, local_normal); 191 let safe_local_normal = select(computed_local_normal, local_normal, dot_alignment < 0.1); 193 let model_rotation_matrix = mat3x3<f32>( 194 instance.world_from_local[0].xyz, 195 instance.world_from_local[1].xyz, 196 instance.world_from_local[2].xyz 199 result.world_normal = normalize(model_rotation_matrix * safe_local_normal); 201 let world_tangent_vec = normalize(model_rotation_matrix * delta_tangent); 203 result.world_tangent = vec4<f32>( 204 normalize(world_tangent_vec - dot(world_tangent_vec, result.world_normal) * result.world_normal), 210#ifdef EDGE_CORRECTION 212 let edge_correction_offset = calculate_edge_correction( 213 result.world_position.xyz, 216 wind.edge_correction_factor 219 result.world_position += vec4<f32>(edge_correction_offset, 0.); 226fn calculate_macro_curve( 227 local_pos: vec3<f32>, 230 instance: InstanceInfo, 232 static_bend: vec2<f32>, 235 var result: CurveResult; 237 let height_range = max(wind.aabb_max.y - wind.aabb_min.y, 0.001); 240 let height_progress = clamp((local_pos.y - wind.aabb_min.y) / height_range, 0.0, 1.0); 242 result.height_factor = height_progress; 245 result.local_wind_dir = vec3<f32>(0.0); 246 var target_bend_vector = vec2<f32>(0.0); 249 target_bend_vector += static_bend; 254 let scale_x = length(instance.world_from_local[0].xyz); 255 let scale_y = length(instance.world_from_local[1].xyz); 256 let scale_z = length(instance.world_from_local[2].xyz); 258 let rotation_matrix = mat3x3<f32>( 259 instance.world_from_local[0].xyz / max(scale_x, 0.001), 260 instance.world_from_local[1].xyz / max(scale_y, 0.001), 261 instance.world_from_local[2].xyz / max(scale_z, 0.001) 264 let world_wind_direction = vec3<f32>(wind.direction.x, 0.0, wind.direction.y); 265 let local_wind_unscaled = transpose(rotation_matrix) * world_wind_direction; 266 result.local_wind_dir = normalize(local_wind_unscaled); 268 let macro_noise_value = clamp(noise.macro_noise, 0.001, 0.999) * 2.0 - 1.0; 270 let scale_compensation = vec2<f32>(1.0 / max(scale_x, 0.001), 1.0 / max(scale_z, 0.001)); 272 let wind_force = vec2<f32>(local_wind_unscaled.x, local_wind_unscaled.z) 275 * scale_compensation; 277 target_bend_vector += wind_force; 280 result.twist = macro_noise_value * wind.twist_strength * height_progress; 284 let total_bend_amount = length(target_bend_vector); 287 let max_allowed_bend = height_range * 0.95; 288 let safe_bend_amount = min(total_bend_amount, max_allowed_bend); 289 let bend_factor = clamp(total_bend_amount / height_range, 0.0, 1.0); 290 let bend_stiffness = 0.33; 293 var tip_height = sqrt(max(height_range * height_range - safe_bend_amount * safe_bend_amount, 0.0)); 296 let stretch_compensation = 1.0 - (bend_factor * 0.1); 297 tip_height *= stretch_compensation; 303 let point_end = vec3<f32>(target_bend_vector.x, tip_height, target_bend_vector.y); 304 let point_start = vec3<f32>(0.0, 0.0, 0.0); 308 let control_point_y_factor = mix(0.5, 0.6, bend_factor); 309 let control_point_y = height_range * control_point_y_factor; 311 let point_control = vec3<f32>( 312 target_bend_vector.x * bend_stiffness, 314 target_bend_vector.y * bend_stiffness 318 let inverse_progress = 1.0 - height_progress; 319 let bezier_position = (inverse_progress * inverse_progress) * point_start 320 + (2.0 * inverse_progress * height_progress) * point_control 321 + (height_progress * height_progress) * point_end; 324 let bezier_tangent = 2.0 * inverse_progress * (point_control - point_start) 325 + 2.0 * height_progress * (point_end - point_control); 328 let cos_twist = cos(result.twist); 329 let sin_twist = sin(result.twist); 330 let twisted_x = local_pos.x * cos_twist - local_pos.z * sin_twist; 331 let twisted_z = local_pos.x * sin_twist + local_pos.z * cos_twist; 334 let spine_delta = bezier_position - vec3<f32>(0.0, local_pos.y - wind.aabb_min.y, 0.0); 336 result.local_pos = vec3<f32>( 337 twisted_x + spine_delta.x, 338 local_pos.y + spine_delta.y, 339 twisted_z + spine_delta.z 342 let slope_xz = vec2<f32>(bezier_tangent.x, bezier_tangent.z) / max(bezier_tangent.y, 0.001); 344 result.slope = vec3<f32>(slope_xz.x, 1.0, slope_xz.y); 349fn apply_micro_details( 351 curve_data: CurveResult, 353 instance: InstanceInfo, 359#ifndef WIND_LOW_QUALITY 361 let forward_dir = curve_data.local_wind_dir; 363 let up_dir = vec3<f32>(0.0, 1.0, 0.0); 364 let right_dir = normalize(cross(forward_dir, up_dir)); 367 let micro_noise_val = (clamp(noise.micro_noise, 0.001, 0.999) * 2.0 - 1.0); 368 let micro_offset = forward_dir * (micro_noise_val * wind.micro_strength * 0.5 * curve_data.height_factor); 371 let s_curve_seed = noise.phase_noise.x * 6.28; 372 let s_curve_lag = curve_data.height_factor * wind.s_curve_frequency; 373 let s_curve_input = instance.wrapped_time * wind.s_curve_speed + s_curve_seed + s_curve_lag; 375 let s_primary_oscillation = sin(s_curve_input); 376 let s_secondary_oscillation = cos(s_curve_input * 0.7) * 0.5; 378 let s_curve_offset = (forward_dir * s_primary_oscillation + right_dir * s_secondary_oscillation) 379 * wind.s_curve_strength 380 * curve_data.height_factor; 383 let bop_seed = noise.phase_noise.y * 6.28; 384 let bop_input = instance.wrapped_time * wind.bop_speed + bop_seed + s_curve_lag; 385 let bop_val = sin(bop_input); 387 let bop_offset = vec3<f32>(0.0, bop_val * wind.bop_strength * curve_data.height_factor, 0.0); 389 final_pos += micro_offset + s_curve_offset + bop_offset; 398 instance: InstanceInfo, 399 local_displaced_pos: vec3<f32>, 400 total_offset: vec3<f32> 402 let billboard_anchor_point = instance.instance_position; 404 let billboard_matrix = calculate_billboard_matrix( 405 billboard_anchor_point, 406 view.world_position.xyz, 407 instance.world_from_local 410 let billboard_base_pos = billboard_anchor_point.xyz + (billboard_matrix * local_displaced_pos); 412 return billboard_base_pos + vec3(0.0, total_offset.y, 0.0); 415fn calculate_billboard_matrix( 416 instance_position: vec4<f32>, 417 camera_world_pos: vec3<f32>, 418 world_from_local: mat4x4<f32> 420 let scale = vec3<f32>( 421 length(world_from_local[0].xyz), 422 length(world_from_local[1].xyz), 423 length(world_from_local[2].xyz) 426 let to_camera_vector = camera_world_pos - instance_position.xyz; 427 let billboard_z = normalize(vec3<f32>(to_camera_vector.x, 0.0, to_camera_vector.z)); 428 let billboard_y = vec3<f32>(0.0, 1.0, 0.0); 429 let billboard_x = normalize(cross(billboard_y, billboard_z)); 431 return mat3x3<f32>(billboard_x * scale.x, billboard_y * scale.y, billboard_z * scale.z); 434fn calculate_edge_correction( 435 world_pos: vec3<f32>, 436 world_normal: vec3<f32>, 438 edge_correction_factor: f32 440 let signed_edge_factor = uv_x * 2.0 - 1.0; 442 let to_camera_dir = normalize(view.world_position.xyz - world_pos); 444 let world_up = vec3<f32>(0.0, 1.0, 0.0); 445 let view_side_dir = normalize(cross(to_camera_dir, world_up)); 448 let normal_dot_view = dot(world_normal, to_camera_dir); 449 let grazing_angle_factor = pow(1.0 - abs(normal_dot_view), 2.0); 452 let top_down_factor = abs(dot(to_camera_dir, world_up)); 453 let top_down_fade = pow(1.0 - top_down_factor, 0.5); 455 let strength = grazing_angle_factor * edge_correction_factor * top_down_fade; 457 let correction_shift = view_side_dir * -signed_edge_factor; 459 return correction_shift * strength;