4#define_import_path aqua::optics 8 mesh_view_bindings::{globals, lights, view}, 10#import bevy_pbr::mesh_view_bindings as view_bindings 11#import aqua::cascade::{DEBUG_MODE_BEAUTY, DEBUG_MODE_BEER_LAMBERT, DEBUG_MODE_REFRACTION_VALIDITY, DEBUG_MODE_SEA_FLOOR, DEBUG_MODE_TRANSMISSION, DEBUG_MODE_UNREFRACTED, DEBUG_MODE_WATER_PATH, LUMINANCE_EPSILON, MIN_NORMAL_Y, capillary_resolved_weight, cascade_layout, godot_fresnel, invocation_extinction, invocation_ripple, sample_planar_reflection, screen_xz_footprint, surface} 12#import aqua::waves::displace::{FFT_JONSWAP_SLOPE_VARIANCE, GERSTNER_SLOPE_VARIANCE, WAVE_NORMALS_SLOPE_VARIANCE, capillary_normal_slope, detail_normal_sample} 13#import aqua::foam::shade::{sample_foam_density} 14#import aqua::shore::water::{blended_water_depth, caustic_bed_radiance} 15#import aqua::light::incident::{GODOT_NORMAL_FADE_RATE, GODOT_NORMAL_MINIMUM_STRENGTH, GODOT_SSS_MODIFIER, GODOT_WATER_ALBEDO, LUMINANCE_WEIGHTS, filtered_primary_light_color, ggx_distribution, safe_normalize, sample_diffuse_environment, sample_environment, smith_masking_shadowing, strongest_incident_directional_light} 16#import bevy_aqua_core::material::{CameraDepthDebug, CameraDepthPath, FoamState, MediumState, NearSurface, PrimaryLightState, SurfaceVertexOutput, TransmissionState} 21const TRANSMISSION_OPAQUE_OPTICAL_DEPTH: f32 = 6.931471806; 27fn unresolved_wave_roughness( 31 lighting_normal_strength: f32, 32 filtered_detail_variance: f32, 34 let footprint = screen_xz_footprint(); 35 let unresolved_wavelength = 2.0 * footprint; 36 var unresolved_variance = 0.0; 37 var resolved_variance = 0.0; 38 for (var band = 0u; band < 5u; band++) { 39 let maximum_wavelength = cascade_layout.cascades[band].max_wavelength; 40 let minimum_wavelength = 0.5 * maximum_wavelength; 41 let unresolved_fraction = clamp( 42 log2(max(unresolved_wavelength / minimum_wavelength, 1.0)), 46 let fft_variance = FFT_JONSWAP_SLOPE_VARIANCE[band]; 47 let band_variance = mix( 48 GERSTNER_SLOPE_VARIANCE[band], 52 unresolved_variance += unresolved_fraction * band_variance; 53 resolved_variance += (1.0 - unresolved_fraction) * band_variance; 56 let lod_blend_energy = 2.0 * ( 57 (1.0 - lod_alpha) * (1.0 - lod_alpha) + lod_alpha * lod_alpha 59 let detail_variance = WAVE_NORMALS_SLOPE_VARIANCE 61 * surface.detail.y * surface.detail.y 62 * surface.detail.z * surface.detail.z; 63 let filtered_variance = min(filtered_detail_variance, detail_variance); 64 unresolved_variance += filtered_variance; 65 resolved_variance += detail_variance - filtered_variance; 66 let capillary_resolved = capillary_resolved_weight(world_xz); 67 let capillary_variance = WAVE_NORMALS_SLOPE_VARIANCE 68 * surface.capillary.y * surface.capillary.y; 69 unresolved_variance += capillary_variance 70 * (1.0 - capillary_resolved * capillary_resolved); 71 resolved_variance += capillary_variance 72 * capillary_resolved * capillary_resolved; 76 let removed_fraction = 1.0 77 - lighting_normal_strength * lighting_normal_strength; 78 var slope_variance = unresolved_variance 79 + removed_fraction * resolved_variance; 80 let grazing_boost = mix(1.0, 1.5, 1.0 - abs(to_view.y)); 81 slope_variance *= surface.reflection.y * grazing_boost; 82 return min(sqrt(max(slope_variance, 0.0)), surface.reflection.w); 85fn deep_water_weight(water_depth: f32) -> f32 { 86 return smoothstep(0.35, surface.shallow_color.a, water_depth); 89fn depth_aware_body_albedo( 91 deep_body_albedo: vec3<f32>, 94 surface.shallow_color.rgb, 96 deep_water_weight(water_depth), 101 world_position: vec4<f32>, 103 geometric_normal: vec3<f32>, 108 let geometric_slope = geometric_normal.xz / max(geometric_normal.y, MIN_NORMAL_Y); 109 let lighting_normal = safe_normalize( 111 geometric_slope.x * GODOT_NORMAL_MINIMUM_STRENGTH, 113 geometric_slope.y * GODOT_NORMAL_MINIMUM_STRENGTH, 117 let view_vertical = abs(to_view.y); 118 let deep_body_albedo = mix( 119 surface.grazing_color.rgb, 120 surface.deep_color.rgb, 125 let body_albedo = depth_aware_body_albedo(water_depth, deep_body_albedo); 126 let diffuse_irradiance = sample_diffuse_environment(vec3(0.0, 1.0, 0.0)); 127 var body = diffuse_irradiance * (body_albedo + GODOT_WATER_ALBEDO); 129 let perceptual_roughness = max(surface.reflection.w, 0.05); 130 let reflection = reflect(-to_view, lighting_normal); 131 var reflected_radiance = sample_environment( 134 perceptual_roughness, 136 let planar = sample_planar_reflection(world_position.xyz, surface_level, lighting_normal); 137 reflected_radiance = mix(reflected_radiance, planar.color, planar.weight); 138 if lights.n_directional_lights > 0u { 139 let light = lights.directional_lights[0u]; 140 let light_direction = safe_normalize( 141 light.direction_to_light, 144 let filtered_light_color = filtered_primary_light_color( 146 light.direction_to_light, 147 light.sun_disk_angular_size, 150 let light_radiance = filtered_light_color * view.exposure; 151 let lambertian = 0.5 * max(dot(lighting_normal, light_direction), 2e-5); 152 body += lambertian * light_radiance * GODOT_WATER_ALBEDO; 154 let dot_nv = max(dot(lighting_normal, to_view), 2e-5); 155 let sss_light_mask = smith_masking_shadowing(surface.sun.y, dot_nv); 156 let sss_near = 0.5 * dot_nv * dot_nv; 157 let sss_height = max(0.0, wave_height + 2.5) 158 * pow(max(dot(light_direction, -to_view), 0.0), 4.0) 160 0.5 - 0.5 * dot(light_direction, lighting_normal), 163 body += (sss_height + sss_near) 164 * GODOT_SSS_MODIFIER / (1.0 + sss_light_mask) 165 * light_radiance * GODOT_WATER_ALBEDO; 166 let light_luminance = max( 167 dot(filtered_light_color, LUMINANCE_WEIGHTS), 170 let light_color = filtered_light_color / light_luminance; 171 let light_strength = clamp(light_luminance / surface.reflection.z, 0.0, 1.0); 172 let sun_roughness = min(sqrt( 173 surface.sun.y * surface.sun.y 174 + perceptual_roughness * perceptual_roughness, 176 let halfway = safe_normalize(light_direction + to_view, lighting_normal); 177 let dot_nl = max(dot(lighting_normal, light_direction), 2e-5); 178 let dot_nv_sun = max(dot(lighting_normal, to_view), 2e-5); 179 let light_mask = smith_masking_shadowing(sun_roughness, dot_nv_sun); 180 let view_mask_sun = smith_masking_shadowing(sun_roughness, dot_nl); 181 let distribution = ggx_distribution( 182 clamp(dot(lighting_normal, halfway), 0.0, 1.0), 185 let geometric_attenuation = 1.0 / (1.0 + light_mask + view_mask_sun); 186 let sun_specular = distribution 187 * geometric_attenuation / (4.0 * dot_nv_sun + 0.1); 188 reflected_radiance += sun_specular 194 let view_alignment = clamp(dot(lighting_normal, to_view), 0.0, 1.0); 195 let reflection_weight = clamp( 196 godot_fresnel(view_alignment) * surface.fresnel.z, 200 return mix(body, reflected_radiance, reflection_weight); 203fn camera_eye_depth(uv: vec2<f32>, raw_depth: f32) -> f32 { 204 let ndc = vec3(uv * vec2(2.0, -2.0) + vec2(-1.0, 1.0), raw_depth); 205 let view_position = view.view_from_clip * vec4(ndc, 1.0); 206 return max(-view_position.z / max(view_position.w, LUMINANCE_EPSILON), 0.0); 209fn empty_camera_depth_path() -> CameraDepthPath { 210 var result: CameraDepthPath; 211 result.path_length = 0.0; 212 result.screen_uv = vec2(0.0); 213 result.scene_z = 0.0; 214 result.has_background = false; 218fn camera_depth_path(in: SurfaceVertexOutput) -> CameraDepthPath { 219 var result = empty_camera_depth_path(); 221 let viewport_origin = view.viewport.xy; 222 let viewport_size = view.viewport.zw; 223 result.screen_uv = clamp( 224 (in.position.xy - viewport_origin) / viewport_size, 228 let scene_raw_depth = prepass_utils::prepass_depth(in.position, 0u); 229 result.has_background = scene_raw_depth > 0.0; 230 result.scene_z = camera_eye_depth(result.screen_uv, scene_raw_depth); 231 let pixel_z = max(-(view.view_from_world * in.world_position).z, 0.0); 232 result.path_length = max(result.scene_z - pixel_z, 0.0); 240fn camera_depth_debug_from_path( 241 in: SurfaceVertexOutput, 243 path: CameraDepthPath, 244) -> CameraDepthDebug { 245 var result: CameraDepthDebug; 246 result.path_length = path.path_length; 247 result.screen_uv = path.screen_uv; 248 result.refracted_uv = path.screen_uv; 249 result.refracted_sample_valid = false; 250 result.has_background = path.has_background; 252 let shallow_gap = min(1.0, 0.5 * path.path_length); 253 let refract_offset = surface.debug.y * normal.xz 254 * shallow_gap / max(path.scene_z, LUMINANCE_EPSILON); 255 result.refracted_uv = clamp(path.screen_uv + refract_offset, vec2(0.0), vec2(1.0)); 256 let refracted_pixel = result.refracted_uv * (view.viewport.zw - vec2(1.0)) 258 let refracted_position = vec4(refracted_pixel, in.position.zw); 259 let refracted_raw_depth = prepass_utils::prepass_depth(refracted_position, 0u); 260 result.refracted_sample_valid = refracted_raw_depth < in.position.z; 267fn opaque_background(subview_uv: vec2<f32>) -> vec3<f32> { 268 let dimensions = vec2<f32>(textureDimensions(view_bindings::view_transmission_texture)); 270 subview_uv * view.viewport.zw + view.viewport.xy 272 return textureSampleLevel( 273 view_bindings::view_transmission_texture, 274 view_bindings::view_transmission_sampler, 280fn resolve_near_surface( 281 in: SurfaceVertexOutput, 283 geometric_normal: vec3<f32>, 287 var normal = geometric_normal; 288 var filtered_detail_variance = 0.0; 289 if mode >= DEBUG_MODE_BEAUTY { 290 let near_weight = 1.0 - far_tier; 291 var resolved_slope = normal.xz / max(normal.y, MIN_NORMAL_Y); 292 let detail = detail_normal_sample( 298 resolved_slope += near_weight * detail.xy; 299 filtered_detail_variance = near_weight * near_weight * detail.z; 300 resolved_slope += near_weight * capillary_normal_slope(in.undisplaced_xz, invocation_ripple()) 301 * capillary_resolved_weight(in.undisplaced_xz); 302 normal = safe_normalize( 303 vec3(resolved_slope.x, 1.0, resolved_slope.y), 307 let lighting_distance = length(in.world_position.xz - view.world_position.xz); 308 let lighting_normal_strength = mix( 309 GODOT_NORMAL_MINIMUM_STRENGTH, 311 exp(-lighting_distance * GODOT_NORMAL_FADE_RATE), 313 let full_slope = normal.xz / max(normal.y, MIN_NORMAL_Y); 314 let lighting_normal = safe_normalize( 316 full_slope.x * lighting_normal_strength, 318 full_slope.y * lighting_normal_strength, 326 lighting_normal_strength, 327 filtered_detail_variance, 331fn sample_water_medium( 332 in: SurfaceVertexOutput, 334 lighting_normal: vec3<f32>, 338 let water_depth = blended_water_depth(in.undisplaced_xz); 339 let view_vertical = abs(to_view.y); 340 let deep_body_albedo = mix( 341 surface.grazing_color.rgb, 342 surface.deep_color.rgb, 347 let body_albedo = depth_aware_body_albedo(water_depth, deep_body_albedo); 348 var diffuse_irradiance = vec3(0.0); 349 if mode >= DEBUG_MODE_BEAUTY { 350 diffuse_irradiance = sample_diffuse_environment(lighting_normal); 352 var foam_density = 0.0; 353 if mode != DEBUG_MODE_SEA_FLOOR { 354 foam_density = sample_foam_density( 369 scene_colour: vec3<f32>, 370 in: SurfaceVertexOutput, 372 primary: PrimaryLightState, 374 let incident = strongest_incident_directional_light( 382 return caustic_bed_radiance( 390 invocation_extinction(), 394fn resolve_transmission( 395 in: SurfaceVertexOutput, 397 scatter_colour: vec3<f32>, 400 primary: PrimaryLightState, 402) -> TransmissionState { 403 var body = scatter_colour; 404 var shared_depth_path = foam.depth_path; 405 var has_shared_depth_path = foam.has_depth_path; 406 if mode >= DEBUG_MODE_WATER_PATH && mode <= DEBUG_MODE_SEA_FLOOR { 408 if !has_shared_depth_path { 409 shared_depth_path = camera_depth_path(in); 410 has_shared_depth_path = true; 412 let depth_debug = camera_depth_debug_from_path(in, normal, shared_depth_path); 413 if mode == DEBUG_MODE_WATER_PATH { 414 let path = clamp(depth_debug.path_length / surface.debug.z, 0.0, 1.0); 415 return TransmissionState(body, vec4(vec3(path), 1.0), true); 417 if mode == DEBUG_MODE_REFRACTION_VALIDITY { 419 vec4(1.0, 0.0, 0.0, 1.0), 420 vec4(0.0, 1.0, 0.0, 1.0), 421 depth_debug.refracted_sample_valid, 423 return TransmissionState(body, output, true); 425 let refraction_enabled = mode == DEBUG_MODE_TRANSMISSION 426 || mode == DEBUG_MODE_BEER_LAMBERT 427 || mode == DEBUG_MODE_SEA_FLOOR; 428 let use_refraction = refraction_enabled 429 && depth_debug.refracted_sample_valid; 430 let background_uv = select( 431 depth_debug.screen_uv, 432 depth_debug.refracted_uv, 435 let scene_colour = opaque_background(background_uv); 436 if mode == DEBUG_MODE_TRANSMISSION || mode == DEBUG_MODE_UNREFRACTED { 437 return TransmissionState(body, vec4(scene_colour, 1.0), true); 442 let lit_scene = illuminate_bed(scene_colour, in, medium, primary); 443 let alpha = 1.0 - exp(-invocation_extinction() * depth_debug.path_length); 444 body = mix(lit_scene, scatter_colour, alpha); 445 if mode == DEBUG_MODE_BEER_LAMBERT { 446 return TransmissionState(body, vec4(body, 1.0), true); 448 } else if mode == DEBUG_MODE_BEAUTY { 449 if !has_shared_depth_path { 450 shared_depth_path = camera_depth_path(in); 451 has_shared_depth_path = true; 453 let depth_path = shared_depth_path; 456 let deep_weight = smoothstep(0.35, surface.shallow_color.a, medium.water_depth); 457 let shallow_extinction_scale = mix(vec3(0.52, 0.42, 0.62), vec3(1.0), deep_weight); 458 let extinction = invocation_extinction() * shallow_extinction_scale; 459 let minimum_extinction = min(extinction.r, min(extinction.g, extinction.b)); 460 let optical_depth = minimum_extinction * depth_path.path_length; 461 if depth_path.has_background 462 && depth_path.path_length > LUMINANCE_EPSILON 463 && optical_depth < TRANSMISSION_OPAQUE_OPTICAL_DEPTH { 464 let depth_debug = camera_depth_debug_from_path(in, normal, depth_path); 465 let use_refraction = depth_debug.refracted_sample_valid; 466 let background_uv = select( 467 depth_debug.screen_uv, 468 depth_debug.refracted_uv, 471 let scene_colour = opaque_background(background_uv); 472 let lit_scene = illuminate_bed(scene_colour, in, medium, primary); 473 let alpha = 1.0 - exp(-extinction * depth_debug.path_length); 474 body = mix(lit_scene, scatter_colour, alpha); 480 return TransmissionState(body, vec4(0.0), false);