2#import aqua::foam::contract::{FOAM_LOD_COUNT, FOAM_TEXTURE_RESOLUTION, FOAM_TEXTURE_RESOLUTION_U32} 5const NO_BED_DEPTH: f32 = 256.0; 6const UV_CENTER: f32 = 0.5; 19 cascades: array<CascadeParams, 6>, 22 bed_transform: vec4<f32>, 28 source_layout: CascadeLayout, 29 target_layout: CascadeLayout, 35@group(0) @binding(0) var source_foam: texture_2d_array<f32>; 36@group(0) @binding(1) var source_sampler: sampler; 37@group(0) @binding(2) var anim_waves: texture_2d_array<f32>; 38@group(0) @binding(3) var waves_sampler: sampler; 39@group(0) @binding(4) var bed_height: texture_2d<f32>; 40@group(0) @binding(5) var target_foam: texture_storage_2d_array<rgba16float, write>; 41@group(0) @binding(6) var<uniform> foam: FoamUniform; 42@group(0) @binding(7) var fft_surface: texture_2d_array<f32>; 44fn world_to_uv(world_xz: vec2<f32>, cascade: CascadeParams) -> vec2<f32> { 45 let coverage = cascade.texel_width * cascade.texture_res; 46 return (world_xz - cascade.center) / coverage + vec2(UV_CENTER); 49fn texel_world(id: vec2<u32>, cascade: CascadeParams) -> vec2<f32> { 50 let uv = (vec2<f32>(id) + vec2(0.5)) / FOAM_TEXTURE_RESOLUTION; 51 let coverage = cascade.texel_width * cascade.texture_res; 52 return cascade.center + (uv - vec2(UV_CENTER)) * coverage; 55fn inside_source(uv: vec2<f32>) -> bool { 56 let radius = UV_CENTER - 1.0 / FOAM_TEXTURE_RESOLUTION; 58 return max(abs(uv.x - UV_CENTER), abs(uv.y - UV_CENTER)) <= radius; 61fn reproject(world_xz: vec2<f32>, slice: u32, source: CascadeLayout) -> f32 { 62 let cascade = source.cascades[slice]; 63 let uv = world_to_uv(world_xz, cascade); 64 if inside_source(uv) { 65 return textureSampleLevel(source_foam, source_sampler, uv, i32(slice), 0.0).r; 67 if slice + 1u < FOAM_LOD_COUNT { 68 let coarse = source.cascades[slice + 1u]; 69 let coarse_uv = world_to_uv(world_xz, coarse); 70 if inside_source(coarse_uv) { 71 return textureSampleLevel( 83fn displacement(world_xz: vec2<f32>, slice: u32) -> vec4<f32> { 84 let cascade = foam.target_layout.cascades[slice]; 85 return textureSampleLevel( 88 world_to_uv(world_xz, cascade), 94fn jacobian_foam_source( 97 cascade: CascadeParams, 99 if foam.step.z != 0u { 100 let determinant = textureSampleLevel( 103 world_to_uv(world_xz, cascade), 107 return clamp(foam.wave.w - determinant, 0.0, 1.0); 109 let center = displacement(world_xz, slice); 110 let offset_x = displacement( 111 world_xz + vec2(cascade.texel_width, 0.0), 114 let offset_z = displacement( 115 world_xz + vec2(0.0, cascade.texel_width), 118 let tangent_x = vec2(cascade.texel_width, 0.0) 119 + offset_x.xz - center.xz; 120 let tangent_z = vec2(0.0, cascade.texel_width) 121 + offset_z.xz - center.xz; 122 let determinant = (tangent_x.x * tangent_z.y - tangent_x.y * tangent_z.x) 123 / (cascade.texel_width * cascade.texel_width); 124 return clamp(foam.wave.w - determinant + 0.7 * center.w, 0.0, 1.0); 127fn averaged_foam_source( 130 cascade: CascadeParams, 132 if foam.step.z == 0u { 133 return jacobian_foam_source(world_xz, slice, cascade); 135 let foam_texel_width = cascade.texel_width 136 * cascade.texture_res / FOAM_TEXTURE_RESOLUTION; 137 let quarter_texel = 0.25 * foam_texel_width; 138 let offset = vec2(quarter_texel); 140 jacobian_foam_source(world_xz - offset, slice, cascade) 141 + jacobian_foam_source( 142 world_xz + vec2(offset.x, -offset.y), 146 + jacobian_foam_source( 147 world_xz + vec2(-offset.x, offset.y), 151 + jacobian_foam_source(world_xz + offset, slice, cascade) 156fn bed_water_depth(world_xz: vec2<f32>) -> f32 { 157 let range = foam.target_layout.bed_range; 161 let uv = (world_xz - foam.target_layout.bed_transform.xy) 162 * foam.target_layout.bed_transform.zw; 163 if any(uv < vec2(0.0)) || any(uv > vec2(1.0)) { 166 let dimensions = vec2<f32>(textureDimensions(bed_height)); 167 let texel_position = uv * (dimensions - vec2(1.0)); 168 let base = vec2<i32>(floor(texel_position)); 169 let fraction = fract(texel_position); 170 let maximum = i32(dimensions.x) - 1; 171 let maximum_y = i32(dimensions.y) - 1; 172 let p00 = clamp(base, vec2(0), vec2(maximum, maximum_y)); 173 let p10 = clamp(base + vec2(1, 0), vec2(0), vec2(maximum, maximum_y)); 174 let p01 = clamp(base + vec2(0, 1), vec2(0), vec2(maximum, maximum_y)); 175 let p11 = clamp(base + vec2(1), vec2(0), vec2(maximum, maximum_y)); 177 textureLoad(bed_height, p00, 0).r, 178 textureLoad(bed_height, p10, 0).r, 182 textureLoad(bed_height, p01, 0).r, 183 textureLoad(bed_height, p11, 0).r, 186 let height = mix(row_0, row_1, fraction.y) * range.y + range.x; 187 return max(range.z - height, 0.0); 190fn update(id: vec3<u32>, use_previous_layout: bool, dt: f32) { 191 if any(id.xy >= vec2<u32>(FOAM_TEXTURE_RESOLUTION_U32)) || id.z >= FOAM_LOD_COUNT { 195 let cascade = foam.target_layout.cascades[slice]; 196 let world_xz = texel_world(id.xy, cascade); 197 var density = reproject(world_xz, slice, foam.target_layout); 198 if use_previous_layout { 199 density = reproject(world_xz, slice, foam.source_layout); 202 density *= max(0.0, 1.0 - foam.wave.y * dt); 204 let center = displacement(world_xz, slice); 205 density += 5.0 * dt * foam.wave.z 206 * averaged_foam_source(world_xz, slice, cascade); 208 var depth = bed_water_depth(world_xz + center.xz) + center.y; 211 let wet_edge = 1.0 - smoothstep(foam.shore.z, 2.0 * foam.shore.z, depth); 212 let breaker_rise = smoothstep(foam.shore.z, foam.shore.w, depth); 213 let breaker_fall = 1.0 - smoothstep(foam.shore.w, foam.shore.x, depth); 214 let shore_source = max(wet_edge, 0.18 * breaker_rise * breaker_fall); 215 density += foam.shore.y * dt * shore_source; 217 density = clamp(density, 0.0, 1.0); 218 textureStore(target_foam, vec2<i32>(id.xy), i32(slice), vec4(density, 0.0, 0.0, 0.0)); 221#ifdef FOAM_REPROJECT_PREVIOUS 222@compute @workgroup_size(8, 8, 1) 223fn main(@builtin(global_invocation_id) id: vec3<u32>) { 224 update(id, true, 0.0); 228#ifdef FOAM_UPDATE_CURRENT 229@compute @workgroup_size(8, 8, 1) 230fn main(@builtin(global_invocation_id) id: vec3<u32>) { 231 update(id, false, foam.wave.x); 235#ifndef FOAM_REPROJECT_PREVIOUS 236#ifndef FOAM_UPDATE_CURRENT 237@compute @workgroup_size(8, 8, 1) 238fn main(@builtin(global_invocation_id) id: vec3<u32>) { 239 update(id, true, foam.wave.x);