shader_type canvas_item;
render_mode unshaded;
// FETCH, BAKED (hyper-games #108 perf, 2026-10-07). ocean.gdshader's vertex() made
// four evaluate_density calls per vertex per frame to estimate fetch (open water vs
// sheltered) -- ~10 of 13.8 ms GPU at 1080p with the sea in view, because the sheet
// is 103k vertices drawn twice (pre-pass + opaque). Fetch varies over kilometres and
// only with the terrain, so it is evaluated here once per texel of a camera-centred
// grid and re-baked only when the camera has moved (Ocean._process). The maths is
// the SAME as the vertex path, kept there behind fetch_baked = false as the reference:
// ocean_debug 6 shows the value either way, for an A/B.
//
// Output R = the ring average a in 0..1; the ocean applies mix(fetch_min, 1, a).
#include "res://shaders/terrain_density.gdshaderinc"
uniform vec2 bake_origin = vec2(0.0); // world XZ of the grid's (0,0) corner
uniform float bake_size = 14000.0; // metres the grid spans
uniform float water_y = 700.0;
uniform float fetch_radius = 1500.0;
uniform float fetch_open_depth = 30.0;
uniform float depth_query_footprint = 25.0;
float water_depth_at(vec2 wxz, float footprint) {
float ridge = 0.0;
vec2 grad = vec2(0.0);
return -evaluate_density(wxz.x, water_y, wxz.y, footprint, ridge, grad);
}
void fragment() {
// UV is at the texel CENTRE, which is where the ocean's bilinear lookup puts it.
vec2 wxz = bake_origin + UV * bake_size;
float fp_coarse = max(fetch_radius * 0.125, depth_query_footprint);
float a = 0.0;
a += smoothstep(0.0, fetch_open_depth, water_depth_at(wxz + vec2( fetch_radius, 0.0), fp_coarse));
a += smoothstep(0.0, fetch_open_depth, water_depth_at(wxz + vec2(-fetch_radius, 0.0), fp_coarse));
a += smoothstep(0.0, fetch_open_depth, water_depth_at(wxz + vec2(0.0, fetch_radius), fp_coarse));
a += smoothstep(0.0, fetch_open_depth, water_depth_at(wxz + vec2(0.0, -fetch_radius), fp_coarse));
COLOR = vec4(a * 0.25, 0.0, 0.0, 1.0);
}