4#define_import_path aqua::foam::shade 6#import bevy_pbr::mesh_view_bindings::globals 8#import aqua::cascade::{CascadeParams, LUMINANCE_EPSILON, LocalLightSample, MIN_SAMPLE_WEIGHT, RiverState, advected_world, capillary_resolved_weight, cascade_layout, foam_data, foam_pattern, foam_pattern_sampler, foam_sampler, lod_count, screen_texture_lod, surface, world_to_uv} 9#import aqua::foam::contract::{FOAM_PATTERN_RESOLUTION, FOAM_TEXTURE_RESOLUTION} 10const INV_PI: f32 = 0.31830988618; 11const CREST_FOAM_WHITE_COLOR: vec4<f32> = vec4( 12 1.0, 0.99634784, 0.97199994, 0.6862745, 15const CREST_FOAM_BUBBLE_COLOR: vec3<f32> = vec3(0.64, 0.83, 0.82); 16const CREST_FOAM_BUBBLE_PARALLAX: f32 = 0.14; 17const CREST_FOAM_BUBBLE_COVERAGE: f32 = 1.68; 18const CREST_FOAM_NORMAL_STRENGTH: f32 = 3.5; 19const CREST_FOAM_SPECULAR_FALLOFF: f32 = 293.0; 20const CREST_FOAM_SPECULAR_BOOST: f32 = 0.15; 23const FINE_FOAM_ROTATION: mat2x2<f32> = mat2x2( 24 vec2(0.798636, 0.601815), 25 vec2(-0.601815, 0.798636), 27const FINE_FOAM_SCROLL_DIRECTION: vec2<f32> = vec2(-0.819152, 0.573576); 28const FINE_FOAM_SCALE: f32 = 0.55; 30const CREST_FOAM_LINEAR_MEAN: f32 = 0.426906; 34fn cubic_weights(value: f32) -> vec4<f32> { 35 let squared = value * value; 36 let cubed = squared * value; 38 -cubed + 3.0 * squared - 3.0 * value + 1.0, 39 3.0 * cubed - 6.0 * squared + 4.0, 40 -3.0 * cubed + 3.0 * squared + 3.0 * value + 1.0, 45fn sample_foam_bicubic(uv: vec2<f32>, layer: i32, resolution: f32) -> f32 { 46 let texel_position = uv * resolution + vec2(0.5); 47 let fraction = fract(texel_position); 48 let wx = cubic_weights(fraction.x); 49 let wy = cubic_weights(fraction.y); 57 vec4(wx.y, wx.w, wy.y, wy.w) / groups 58 + vec4(-1.5, 0.5, -1.5, 0.5) 59 + floor(texel_position).xxyy 62 groups.x / (groups.x + groups.y), 63 groups.z / (groups.z + groups.w), 99 return mix(lower, upper, blend.y); 102fn sample_foam_cascade(world_xz: vec2<f32>, cascade: CascadeParams, layer: i32) -> f32 { 103 let uv = world_to_uv(world_xz, cascade); 104 let bilinear = textureSampleLevel( 112 if surface.reflection.x < 0.5 || surface.debug.w > 0.5 { 115 let bicubic = sample_foam_bicubic(uv, layer, FOAM_TEXTURE_RESOLUTION); 116 let coverage = cascade.texel_width * cascade.texture_res; 117 let pixels_per_meter = FOAM_TEXTURE_RESOLUTION / coverage; 118 return mix(bicubic, bilinear, min(1.0, pixels_per_meter * 0.1)); 121fn sample_foam_density(world_xz: vec2<f32>, lod: u32, alpha: f32) -> f32 { 122 let smaller = cascade_layout.cascades[lod]; 123 let bigger = cascade_layout.cascades[lod + 1u]; 124 let smaller_weight = (1.0 - alpha) * smaller.weight; 125 let bigger_weight = (1.0 - smaller_weight) * bigger.weight; 127 if smaller_weight > MIN_SAMPLE_WEIGHT { 128 density += smaller_weight 129 * sample_foam_cascade(world_xz, smaller, i32(lod)); 131 if bigger_weight > MIN_SAMPLE_WEIGHT && lod + 1u < lod_count() { 132 density += bigger_weight 133 * sample_foam_cascade(world_xz, bigger, i32(lod + 1u)); 135 return clamp(density, 0.0, 1.0); 139 advected_xz: vec2<f32>, 143 sample_offset: vec2<f32>, 145 let cascade = cascade_layout.cascades[lod]; 146 let texture_scale = surface.foam.x * cascade.scale / 25.0; 150 let offset = vec2(globals.time / 10.0) + sample_offset; 151 let pattern_xz = advected_xz; 152 let texture_width = textureDimensions(foam_pattern).x; 153 let near_lod = screen_texture_lod(texture_scale / 1.25, texture_width); 154 let near = textureSampleLevel( 156 foam_pattern_sampler, 157 (1.25 * pattern_xz + offset) / texture_scale, 160 let far_scale = 2.0 * texture_scale; 161 let far_lod = screen_texture_lod(far_scale / 1.25, texture_width); 162 let far = textureSampleLevel( 164 foam_pattern_sampler, 165 (1.25 * pattern_xz + offset) / far_scale, 168 var pattern = mix(near, far, alpha); 169 let fine_scroll = FINE_FOAM_SCROLL_DIRECTION * globals.time / 17.0; 170 let fine_coordinates = 171 FINE_FOAM_ROTATION * (1.25 * pattern_xz + sample_offset) + fine_scroll; 172 let fine_scale = FINE_FOAM_SCALE * texture_scale; 173 let fine_lod = screen_texture_lod(fine_scale / 1.25, texture_width); 174 let fine = textureSampleLevel( 176 foam_pattern_sampler, 177 fine_coordinates / fine_scale, 182 let fine_modulation = 1.0 + 0.65 * (fine - CREST_FOAM_LINEAR_MEAN); 183 let fine_weight = capillary_resolved_weight(advected_xz); 184 let modulated_pattern = pattern * mix(1.0, fine_modulation, fine_weight); 186 pattern = select(pattern, modulated_pattern, fine_weight > 0.0); 187 let black_point = clamp(1.0 - density, 0.0, 1.0); 188 return smoothstep(black_point, black_point + surface.foam.y, pattern); 192fn river_streak_density(state: RiverState, world_xz: vec2<f32>, lod: u32, alpha: f32) -> f32 { 196 let speed = length(state.sample.xy); 198 let margin_ratio = clamp(state.sample.z / 8.0, 0.0, 1.0); 199 let strength = (1.0 - margin_ratio) * clamp(speed / 1.6 - 0.2, 0.0, 1.0); 200 if strength <= 0.001 { 203 let dir = state.flow / max(speed, 1e-4); 204 let along = dot(dir, world_xz) / (1.0 + 0.9 * min(speed, 4.0)); 205 let across = dot(vec2(-dir.y, dir.x), world_xz); 208 return surface_foam_mask( 209 advected_world(vec2(along, across * 1.6)), 217fn foam_bubble_colour( 218 displaced_xz: vec2<f32>, 219 undisplaced_xz: vec2<f32>, 223 surface_normal: vec3<f32>, 225 ambient_radiance: vec3<f32>, 227 let wind_direction = vec2(0.866, 0.5); 228 let bubble_world = mix(undisplaced_xz, displaced_xz, 0.7) 229 + 0.5 * globals.time * wind_direction; 230 let bubble_uv = bubble_world / surface.foam.x 231 + 0.125 * surface_normal.xz; 232 let parallax = -CREST_FOAM_BUBBLE_PARALLAX * to_view.xz 233 / max(dot(surface_normal, to_view), LUMINANCE_EPSILON); 234 let smaller = cascade_layout.cascades[lod]; 235 let bigger = cascade_layout.cascades[min(lod + 1u, lod_count())]; 236 let smaller_sample = textureSampleLevel( 238 foam_pattern_sampler, 239 (0.74 * bubble_uv + parallax) / (smaller.scale / 25.0), 242 let bigger_sample = textureSampleLevel( 244 foam_pattern_sampler, 245 (0.74 * bubble_uv + parallax) / (bigger.scale / 25.0), 248 let bubble_texture = mix(smaller_sample, bigger_sample, alpha); 249 let coverage = clamp(density * CREST_FOAM_BUBBLE_COVERAGE, 0.0, 1.0); 250 return bubble_texture * CREST_FOAM_BUBBLE_COLOR 251 * coverage * ambient_radiance; 255 sample: LocalLightSample, 256 foam_normal: vec3<f32>, 259 let foam_ndl = max(dot(foam_normal, sample.direction), 0.0); 260 let foam_reflection = reflect(-to_view, foam_normal); 261 let diffuse = CREST_FOAM_WHITE_COLOR.rgb 262 * INV_PI * surface.foam.z * sample.radiance * foam_ndl; 264 max(dot(foam_reflection, sample.direction), 0.0), 265 CREST_FOAM_SPECULAR_FALLOFF, 266 ) * CREST_FOAM_SPECULAR_BOOST * sample.radiance; 267 return diffuse + specular;