shader_type spatial; render_mode blend_add, depth_draw_never, cull_disabled, unshaded; // Marine snow: camera-facing soft discs drawn by GPUParticles3D. Each particle is a // unit quad; the flake is a radial falloff in UV. Brightness follows the daylight of // the water column (so flakes dim with depth) and fades in and out over the life of // the particle through COLOR.a set by the process material. #include "res://game/world/sites/water_light.gdshaderinc" uniform vec3 flake_color : source_color = vec3(0.78, 0.86, 0.9); uniform float flake_strength = 1.4; uniform vec3 water_absorption_per_m = vec3(0.11, 0.04, 0.032); uniform float reference_depth_m = 24.0; uniform float minimum_daylight = 0.08; varying float brightness; void vertex() { // Billboard: keep the particle's world position, face the camera. vec3 world_origin = (MODEL_MATRIX * vec4(0.0, 0.0, 0.0, 1.0)).xyz; float size = length(MODEL_MATRIX[0].xyz); mat3 view_basis = mat3(INV_VIEW_MATRIX); vec3 world = world_origin + (view_basis[0] * VERTEX.x + view_basis[1] * VERTEX.y) * size; VERTEX = (VIEW_MATRIX * vec4(world, 1.0)).xyz; NORMAL = (VIEW_MATRIX * vec4(view_basis[2], 0.0)).xyz; vec3 transmittance = water_transmittance(-world_origin.y, water_absorption_per_m, reference_depth_m); brightness = water_daylight(transmittance, minimum_daylight) * COLOR.a; } void fragment() { float radial = length(UV - vec2(0.5)) * 2.0; float disc = 1.0 - smoothstep(0.35, 1.0, radial); ALBEDO = flake_color * disc * brightness * flake_strength; ALPHA = disc; }