1const FFT_RESOLUTION: u32 = 256u; 2const LOD_COUNT: u32 = 5u; 3const ATTENUATION_BINS: u32 = 4u; 15 cascades: array<CascadeParams, 6>, 18 bed_transform: vec4<f32>, 23 cascade_layout: CascadeLayout, 30const NO_BED_DEPTH: f32 = 256.0; 36fn bed_water_depth(world_xz: vec2<f32>) -> f32 { 37 let range = fft.cascade_layout.bed_range; 41 let uv = (world_xz - fft.cascade_layout.bed_transform.xy) 42 * fft.cascade_layout.bed_transform.zw; 43 if any(uv < vec2(0.0)) || any(uv > vec2(1.0)) { 46 let dimensions = vec2<u32>(textureDimensions(bed_height)); 47 let maximum = vec2<i32>(dimensions - vec2<u32>(1u)); 48 let texel = clamp(vec2<i32>(round(uv * vec2<f32>(maximum))), vec2(i32(0)), maximum); 49 let height = f32(textureLoad(bed_height, texel, 0).r) * range.y + range.x; 50 return max(range.z - height, 0.0); 53@group(0) @binding(0) var height_x: texture_2d_array<f32>; 54@group(0) @binding(1) var z_field: texture_2d_array<f32>; 55@group(0) @binding(2) var bed_height: texture_2d<f32>; 56@group(0) @binding(3) var output: texture_storage_2d_array<rgba16float, write>; 57@group(0) @binding(4) var<uniform> fft: FftUniform; 59fn shoaling_weights(depth: f32, wave_number: f32) -> vec2<f32> { 60 let relative_depth = clamp(depth * wave_number / 3.141592653589793, 0.0, 1.0); 61 let vertical_base = smoothstep(0.0, 1.0, relative_depth); 62 let breaker = 4.0 * vertical_base * (1.0 - vertical_base); 63 let vertical = vertical_base * (1.0 + 0.18 * breaker); 64 let chop_ratio = mix(0.55, 1.0, smoothstep(0.15, 0.85, vertical_base)); 65 return vec2(vertical * chop_ratio, vertical); 68@compute @workgroup_size(8, 8, 1) 69fn resolve(@builtin(global_invocation_id) id: vec3<u32>) { 70 if any(id.xy >= vec2<u32>(FFT_RESOLUTION)) || id.z >= LOD_COUNT { return; } 71 let bins = u32(fft.mode.x); 72 let normalization = 1.0 / f32(FFT_RESOLUTION * FFT_RESOLUTION); 73 let cascade = fft.cascade_layout.cascades[id.z]; 74 var displacement = vec3(0.0); 78 let packed = textureLoad(height_x, vec2<i32>(id.xy), i32(id.z), 0); 79 let z = textureLoad(z_field, vec2<i32>(id.xy), i32(id.z), 0).x; 80 displacement = vec3(packed.z, packed.x, z) * normalization; 82 let coverage = cascade.texel_width * cascade.texture_res; 83 let uv = (vec2<f32>(id.xy) + vec2(0.5)) / vec2<f32>(cascade.texture_res); 84 let depth = bed_water_depth(coverage * (uv - vec2(0.5)) + cascade.center); 85 for (var bin = 0u; bin < bins; bin += 1u) { 86 let layer = id.z * bins + bin; 87 let packed = textureLoad(height_x, vec2<i32>(id.xy), i32(layer), 0); 88 let z = textureLoad(z_field, vec2<i32>(id.xy), i32(layer), 0).x; 89 let octave_fraction = (f32(bin) + 0.5) / f32(bins); 90 let representative_wavelength = 0.5 * cascade.max_wavelength 91 * exp2(octave_fraction); 92 let wave_number = 2.0 * 3.141592653589793 / representative_wavelength; 93 let shoaling = shoaling_weights(depth, wave_number); 94 let attenuation = mix(vec2(1.0), shoaling, fft.params.y); 96 packed.z * attenuation.x, 97 packed.x * attenuation.y, 102 textureStore(output, vec2<i32>(id.xy), i32(id.z), vec4(displacement, 0.0));