10#define_import_path aqua::cascade 16 clustered_forward as clustering, 20 mesh_view_bindings::{light_probes, lights, view}, 21 view_transformations::position_world_to_clip, 23#import bevy_pbr::mesh_view_bindings as view_bindings 26const CASCADE_COUNT: u32 = 6u; 27const VERTEX_SNAP_MULTIPLIER: f32 = 2.0; 28const COARSE_GRID_MULTIPLIER: f32 = 4.0; 29const LOD_TRANSITION_START: f32 = 1.0; 31const MORPH_BLACK_POINT: f32 = 0.05; 32const MORPH_FADE_SIDES: f32 = 2.0; 33const MORPH_INNER_RADIUS: f32 = 0.375; 35const GRID_CELL_CENTER: f32 = 0.5; 36const UV_CENTER: f32 = 0.5; 37const MIN_SAMPLE_WEIGHT: f32 = 0.001; 38const MIN_NORMAL_Y: f32 = 0.0001; 39const SAFE_LENGTH_SQUARED: f32 = 1e-8; 40const LUMINANCE_EPSILON: f32 = 0.0001; 42const DEBUG_MODE_WATER_PATH: u32 = 1u; 43const DEBUG_MODE_REFRACTION_VALIDITY: u32 = 2u; 44const DEBUG_MODE_TRANSMISSION: u32 = 3u; 45const DEBUG_MODE_UNREFRACTED: u32 = 4u; 46const DEBUG_MODE_BEER_LAMBERT: u32 = 5u; 47const DEBUG_MODE_SEA_FLOOR: u32 = 6u; 48const DEBUG_MODE_BEAUTY: u32 = 7u; 49const DEBUG_MODE_REFLECTION: u32 = 8u; 50const DEBUG_MODE_FOAM: u32 = 9u; 51const DEBUG_MODE_WAVE_HEIGHT: u32 = 10u; 52const DEBUG_MODE_LIGHT_RADIANCE: u32 = 11u; 53const DEBUG_MODE_REFLECTION_FRACTION: u32 = 12u; 54const DEBUG_MODE_FAR_TIER: u32 = 13u; 56const CREST_SSS_MAXIMUM: f32 = 0.6; 57const CREST_SSS_RANGE: f32 = 0.12; 58const CREST_SSS_UNCOMPRESSED: f32 = CREST_SSS_MAXIMUM - CREST_SSS_RANGE; 71 cascades: array<CascadeParams, CASCADE_COUNT>, 74 bed_transform: vec4<f32>, 79struct PlanarReflectionView { 80 view_projection: mat4x4<f32>, 84struct PlanarReflectionParams { 85 views: array<PlanarReflectionView, 2>, 90struct PlanarReflectionSample { 96const PLANAR_PROJECTION_GUARD: f32 = 0.03; 99 deep_color: vec4<f32>, 100 grazing_color: vec4<f32>, 101 shallow_color: vec4<f32>, 103 reflection: vec4<f32>, 106 fog_density: vec4<f32>, 107 sea_floor: vec4<f32>, 111 capillary: vec4<f32>, 113 advection: vec4<f32>, 127 aabb_size: vec4<f32>, 134@group(#{MATERIAL_BIND_GROUP}) @binding(0) var lod_data: texture_2d_array<f32>; 135@group(#{MATERIAL_BIND_GROUP}) @binding(1) var lod_sampler: sampler; 136@group(#{MATERIAL_BIND_GROUP}) @binding(2) var<uniform> cascade_layout: CascadeLayout; 137@group(#{MATERIAL_BIND_GROUP}) @binding(3) var<uniform> surface: SurfaceParams; 138@group(#{MATERIAL_BIND_GROUP}) @binding(4) var bed_height: texture_2d<f32>; 139@group(#{MATERIAL_BIND_GROUP}) @binding(5) var detail_normal: texture_2d<f32>; 140@group(#{MATERIAL_BIND_GROUP}) @binding(6) var detail_sampler: sampler; 141@group(#{MATERIAL_BIND_GROUP}) @binding(7) var foam_data: texture_2d_array<f32>; 142@group(#{MATERIAL_BIND_GROUP}) @binding(8) var foam_sampler: sampler; 143@group(#{MATERIAL_BIND_GROUP}) @binding(9) var foam_pattern: texture_2d<f32>; 144@group(#{MATERIAL_BIND_GROUP}) @binding(10) var foam_pattern_sampler: sampler; 145@group(#{MATERIAL_BIND_GROUP}) @binding(11) var fft_surface: texture_2d_array<f32>; 148const MAX_BODIES: u32 = 16u; 156 bodies: array<BodyParams, MAX_BODIES>, 159@group(#{MATERIAL_BIND_GROUP}) @binding(15) var<uniform> field_params: FieldParams; 160@group(#{MATERIAL_BIND_GROUP}) @binding(16) var field_maps: texture_2d_array<f32>; 161@group(#{MATERIAL_BIND_GROUP}) @binding(17) var field_sampler: sampler; 162@group(#{MATERIAL_BIND_GROUP}) @binding(19) var reflection_a: texture_2d<f32>; 163@group(#{MATERIAL_BIND_GROUP}) @binding(20) var reflection_sampler: sampler; 164@group(#{MATERIAL_BIND_GROUP}) @binding(21) var reflection_b: texture_2d<f32>; 165@group(#{MATERIAL_BIND_GROUP}) @binding(22) var<uniform> planar_reflections: PlanarReflectionParams; 167@group(#{MATERIAL_BIND_GROUP}) @binding(23) var caustics_texture: texture_2d<f32>; 168@group(#{MATERIAL_BIND_GROUP}) @binding(24) var caustics_sampler: sampler; 170fn sample_planar_reflection( 171 world_position: vec3<f32>, 173 surface_normal: vec3<f32>, 174) -> PlanarReflectionSample { 175 if planar_reflections.view_count == 0u { 176 return PlanarReflectionSample(vec3(0.0), 0.0); 179 if planar_reflections.view_count > 1u 180 && abs(surface_level - planar_reflections.views[1].level) 181 < abs(surface_level - planar_reflections.views[0].level) { 184 let view = planar_reflections.views[index]; 185 let clip = view.view_projection * vec4(world_position, 1.0); 187 return PlanarReflectionSample(vec3(0.0), 0.0); 189 let ndc = clip.xy / clip.w; 190 let projected_uv = vec2(ndc.x, -ndc.y) * 0.5 + 0.5; 192 max(-projected_uv.x, projected_uv.x - 1.0), 193 max(-projected_uv.y, projected_uv.y - 1.0), 195 if outside >= PLANAR_PROJECTION_GUARD { 196 return PlanarReflectionSample(vec3(0.0), 0.0); 198 let dimensions = vec2<f32>(textureDimensions(reflection_a)); 199 let half_texel = 0.5 / dimensions; 200 let projected_edge = min( 201 min(projected_uv.x, projected_uv.y), 202 min(1.0 - projected_uv.x, 1.0 - projected_uv.y), 206 let distortion_guard = smoothstep( 208 planar_reflections.distortion + max(half_texel.x, half_texel.y), 211 var uv = projected_uv 212 + vec2(surface_normal.x, -surface_normal.z) 213 * planar_reflections.distortion * distortion_guard; 214 uv = clamp(uv, half_texel, vec2(1.0) - half_texel); 215 var sample = textureSampleLevel( 222 sample = textureSampleLevel( 231 let weight = 1.0 - smoothstep(0.0, PLANAR_PROJECTION_GUARD, max(outside, 0.0)); 232 return PlanarReflectionSample(sample.rgb, weight); 238var<private> effective_flow: vec2<f32> = vec2(0.0, 0.0); 239var<private> effective_time: f32 = 0.0; 241var<private> xz_footprint: f32 = 0.0; 243fn set_xz_footprint(value: f32) { 244 xz_footprint = value; 247fn screen_xz_footprint() -> f32 { 253fn screen_texture_lod(metres_per_repeat: f32, texture_width: u32) -> f32 { 254 let texels_per_pixel = 255 screen_xz_footprint() * f32(texture_width) / max(metres_per_repeat, 1e-6); 256 return max(log2(max(texels_per_pixel, 1.0)), 0.0); 261var<private> river_ripple_scale: f32 = 1.0; 265var<private> invocation_bounded: f32 = 0.0; 266var<private> invocation_river: f32 = 0.0; 267var<private> invocation_optics_a: vec4<f32> = vec4(0.0); 268var<private> invocation_optics_b: vec4<f32> = vec4(0.0); 273var<private> body_extinction: vec3<f32> = vec3(0.0); 274var<private> body_scatter_scale: f32 = 1.0; 278var<private> fragment_river: vec4<f32> = vec4(0.0); 281struct LocalLightSample { 282 direction: vec3<f32>, 299fn begin_invocation(bounded: bool, params: BodyParams) { 300 invocation_bounded = select(0.0, 1.0, bounded); 301 invocation_river = params.flags.y; 302 invocation_optics_a = params.optics_a; 303 invocation_optics_b = params.optics_b; 307fn set_effective_flow(flow: vec2<f32>) { 308 effective_flow = flow; 311fn set_effective_time(time: f32) { 312 effective_time = time; 316fn set_fragment_river(sample: vec4<f32>) { 317 fragment_river = sample; 322fn set_body_optics(extinction: vec3<f32>, scatter_scale: f32) { 323 body_extinction = extinction; 324 body_scatter_scale = scatter_scale; 328fn set_river_ripple(scale: f32) { 329 river_ripple_scale = scale; 332fn invocation_extinction() -> vec3<f32> { 333 return body_extinction; 336fn invocation_scatter_scale() -> f32 { 337 return body_scatter_scale; 340fn invocation_river_state() -> RiverState { 342 invocation_bounded > 0.5 && invocation_river > 0.5, 348fn invocation_ripple() -> f32 { 349 return river_ripple_scale; 353fn advected_world(world_xz: vec2<f32>) -> vec2<f32> { 354 return world_xz - effective_flow * effective_time; 359fn field_uv(world_xz: vec2<f32>) -> vec2<f32> { 360 return (world_xz - field_params.region.xy) 361 / max(field_params.region.zw, vec2(1e-4)); 365fn sample_field_level(world_xz: vec2<f32>) -> vec2<f32> { 366 return textureSampleLevel(field_maps, field_sampler, field_uv(world_xz), 0, 0.0).xy; 370fn sample_field_flow(world_xz: vec2<f32>) -> vec4<f32> { 371 return textureSampleLevel(field_maps, field_sampler, field_uv(world_xz), 1, 0.0); 376fn owning_body(slot: u32) -> BodyParams { 378 return field_params.bodies[slot - 1u]; 380 return field_params.bodies[0]; 383fn lod_count() -> u32 { 384 return u32(cascade_layout.center.w); 387fn smootherstep01(value: f32) -> f32 { 388 let x = clamp(value, 0.0, 1.0); 389 return x * x * x * (x * (x * 6.0 - 15.0) + 10.0); 392fn far_tier_weight(base_world_position: vec3<f32>) -> f32 { 393 let distance = length(base_world_position - view.world_position.xyz); 394 return smootherstep01( 395 (distance - surface.far_tier.x) 396 / max(surface.far_tier.y - surface.far_tier.x, 1.0), 400fn lod_alpha(world_xz: vec2<f32>, cascade: CascadeParams) -> f32 { 401 let offset = abs(world_xz - cascade_layout.center.xy); 403 let chebyshev_distance = max(offset.x, offset.y); 404 let raw_alpha = chebyshev_distance / cascade.scale - LOD_TRANSITION_START; 405 let black_point = MORPH_BLACK_POINT; 406 let fade_width = 1.0 - MORPH_FADE_SIDES * black_point; 407 return clamp((raw_alpha - black_point) / fade_width, 0.0, 1.0); 410fn snap_and_transition( 412 object_xz: vec2<f32>, 413 cascade: CascadeParams, 415 let grid_width = cascade.texel_width; 416 let snap_width = VERTEX_SNAP_MULTIPLIER * grid_width; 417 var transitioned = world_xz - fract(object_xz / snap_width) * snap_width; 418 let alpha = lod_alpha(transitioned, cascade); 420 let coarse_grid = COARSE_GRID_MULTIPLIER * grid_width; 421 let offset = fract(transitioned / coarse_grid) - vec2(GRID_CELL_CENTER); 422 if abs(offset.x) < MORPH_INNER_RADIUS { 423 transitioned.x += offset.x * alpha * coarse_grid; 425 if abs(offset.y) < MORPH_INNER_RADIUS { 426 transitioned.y += offset.y * alpha * coarse_grid; 428 return vec3(transitioned, alpha); 431fn world_to_uv(world_xz: vec2<f32>, cascade: CascadeParams) -> vec2<f32> { 432 let coverage = cascade.texel_width * cascade.texture_res; 433 return (world_xz - cascade.center) / coverage + vec2(UV_CENTER); 441fn sample_displacement( 446 let sampled_xz = advected_world(world_xz); 447 let smaller = cascade_layout.cascades[lod]; 448 let bigger = cascade_layout.cascades[lod + 1u]; 449 let smaller_weight = (1.0 - alpha) * smaller.weight; 450 let bigger_weight = (1.0 - smaller_weight) * bigger.weight; 451 var displacement = vec3(0.0); 453 if smaller_weight > MIN_SAMPLE_WEIGHT { 454 let uv = world_to_uv(sampled_xz, smaller); 455 displacement += smaller_weight 456 * textureSampleLevel(lod_data, lod_sampler, uv, i32(lod), 0.0).xyz; 458 if bigger_weight > MIN_SAMPLE_WEIGHT { 459 let uv = world_to_uv(sampled_xz, bigger); 460 displacement += bigger_weight 461 * textureSampleLevel(lod_data, lod_sampler, uv, i32(lod + 1u), 0.0).xyz; 466fn flow_frame(world_xz: vec2<f32>) -> vec2<f32> { 467 let speed = length(effective_flow); 468 if !(invocation_bounded > 0.5 && invocation_river > 0.5) || speed < 0.05 { 471 let dir = effective_flow / speed; 472 let along = dot(dir, world_xz) / (1.0 + 0.55 * min(speed, 4.5)); 473 let across = dot(vec2(-dir.y, dir.x), world_xz); 474 return vec2(along, across * 1.35); 477fn capillary_resolved_weight(world_xz: vec2<f32>) -> f32 { 478 let distance_to_view = length(world_xz - view.world_position.xz); 479 return 1.0 - smoothstep( 489fn godot_fresnel(view_alignment: f32) -> f32 { 495 let body_active = invocation_bounded > 0.5 && invocation_optics_a.w > 0.5; 496 let sun_roughness = select( 498 invocation_optics_b.y, 499 body_active && invocation_optics_b.y >= 0.0, 501 let plain_schlick = planar_reflections.view_count > 0u 502 || (body_active && invocation_optics_b.z > 0.5); 503 let exponent = select( 504 surface.fresnel.y * exp(-2.69 * sun_roughness), 508 let damping = select( 509 1.0 + 22.7 * pow(sun_roughness, 1.5), 513 let rough = pow(max(0.0, 1.0 - view_alignment), exponent) / damping; 514 return mix(rough, 1.0, surface.fresnel.x);