T03. Реки и озёра из OSM на рельефе (VR-9)

Цель: реки, ручьи и озёра из data/osm/<id>.json видны на земле непрерывными линиями нужной ширины — ориентиры для навигации.

Контекст: docs/guide/world-objects.md («Формат data/osm», «Что не рисуется»), tools/terrain/rivers.py, tools/osm/ (pack_water — только читать), scripts/terrain/terrain.gdshader (вода), маска «деталь 10 м» из T02, docs/guide/terrain.md. Владения: tools/terrain/osm_water.py (новый), data/terrain/*/*_detail10.png (канал G), scripts/terrain/{terrain.gdshader, terrain_common.gdshaderinc, terrain_renderer.gd, surface_layer.gd, terrain.gd}, tests/terrain/test_surface.gd, docs/guide/terrain.md. Не трогать: configs/world.json (владелец волны — T04), data/osm/ (группа 6; нет воды в файле — запрос группе 6).

Шаги

  1. osm_water.py <id>: реки/ручьи/каналы → полосы со сглаженным краем, ширина: тег width, иначе river 25 м, canal 6, stream 4; озёра — полигоны (с дырами). Запись в канал G маски 10 м; параметры — аргументы/константы скрипта, описать в docs.
  2. Шейдер: вода = max(класс «вода» WorldCover, G); узкие ручьи < пикселя — затемнение полосой (fwidth), без мерцания; берег — тонкая полоса мокрого грунта/гальки; блеск прежний (water_color, water_roughness).
  3. surface_at = вода, где G ≥ 0,5 (термики над водой слабые — VR-4). Маски стока rivers.py — только запасной путь (FR-17).
  4. Перегенерировать 4 локации; бюджет данных ≤ 15 МБ.

Критерий приёмки

  • S4 (1000 м над Урсулом): река видна непрерывно по всему кадру (профиль яркости поперёк реки в 5 местах: провал ≥ 15 %).
  • U1: контур озера Аушкуль — IoU с полигоном OSM ≥ 0,85 (тест по маске).
  • Тест: 50 точек на осевых OSM-рек — surface_at = вода ≥ 90 %; точки в 100 м от оси — не вода ≥ 95 %.
  • GPU «рельеф» ≤ результат T02 + 0,05 мс; тесты tests/terrain зелёные.

Зависимости: T02 (маска 10 м). Модель: sonnet. Размер: M.