shader_type spatial; render_mode cull_disabled, depth_draw_opaque; // Seagrass tufts and sea fans as alpha-cut billboards instanced by MultiMesh. The mesh // is unit sized (y from 0 to 1); the instance transform gives size and heading, the // instance COLOR the species tint, INSTANCE_CUSTOM.x the sway phase and // INSTANCE_CUSTOM.y the sway weight (grass bends, fans barely). Daylight follows the // same water column as the seabed; the submarine's projectors are not attenuated. #include "res://game/world/sites/water_light.gdshaderinc" uniform sampler2D albedo_map : source_color, filter_linear_mipmap; 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.05; uniform float sway_amplitude = 0.09; uniform float sway_speed = 0.8; uniform float alpha_threshold = 0.5; uniform float translucency = 0.7; varying vec3 world_position; varying float daylight; varying vec3 chroma; void vertex() { float phase = INSTANCE_CUSTOM.x * TAU; float weight = INSTANCE_CUSTOM.y * VERTEX.y * VERTEX.y; float swing = sin(TIME * sway_speed + phase) + 0.35 * sin(TIME * sway_speed * 2.3 + phase * 1.7); VERTEX.x += swing * sway_amplitude * weight; VERTEX.z += cos(TIME * sway_speed * 0.7 + phase) * sway_amplitude * 0.5 * weight; world_position = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xyz; vec3 transmittance = water_transmittance(-world_position.y, water_absorption_per_m, reference_depth_m); daylight = water_daylight(transmittance, minimum_daylight); chroma = water_chroma(transmittance, water_absorption_per_m, reference_depth_m); } void fragment() { vec4 sample = texture(albedo_map, UV); ALPHA = sample.a; ALPHA_SCISSOR_THRESHOLD = alpha_threshold; ALBEDO = sample.rgb * COLOR.rgb * chroma; if (!FRONT_FACING) { NORMAL = -NORMAL; } AO = daylight; AO_LIGHT_AFFECT = 0.35; ROUGHNESS = 0.85; METALLIC = 0.0; } void light() { float sun = water_sun_factor(LIGHT_IS_DIRECTIONAL, daylight); // Thin blades and fan nets let light through and are lit from both faces: the // lambert term is wrapped around the blade, so a vertical blade under an // overhead sun is not black. float facing = dot(NORMAL, LIGHT); float lambert = clamp(facing, 0.0, 1.0); float wrapped = clamp(abs(facing) * 0.5 + 0.5, 0.0, 1.0) * translucency; DIFFUSE_LIGHT += (lambert + wrapped) * ATTENUATION * LIGHT_COLOR * ALBEDO * sun / PI; }