# HD-рендер AirDef: устройство, статус, план Документ для передачи работы (человеку или агенту). Ведётся по ходу разработки: каждый этап, попавший в `main`, отмечается здесь вместе с коммитом. Если что-то в коде расходится с этим текстом — прав код, а текст надо поправить. ## Что это HD — третий пресет графики мода (`/airdef shader off|on|hd`): отложенное освещение в стиле шейдерпаков (BSL/Complementary-класс), но написанное с нуля внутри нашего форка Horizon (Minecraft 26.3 на Rust/wgpu). Код шейдерпаков (BSL, Complementary, Photon, Iris/OptiFine) **не копируем**: их лицензии запрещают перенос, а в Horizon действует правило clean-room. Пишем по знанию техник (статьи, общеизвестные алгоритмы). Пресеты должны оставаться: `off` (ваниль), `on` (пост-эффекты мода), `hd` (этот рендер), позже `rt` (аппаратная трассировка, отдельно). ## Где код | Что | Где | |---|---| | Весь HD-конвейер: цели, проходы, WGSL-шейдеры (строками), тайлы света, AO, тени, bloom, tonemap, TAA | `horizon/crates/horizon-client/src/gfx/hd.rs` | | Встраивание в кадр: G-буфер-проход, каскады теней, вызовы `hd.light` / `hd.finish`, джиттер, тайминги | `horizon/crates/horizon-client/src/gfx.rs` (`Renderer::render`, ищи `hd_on`, `AirDef fork:`) | | G-буфер террейна: `fs_gbuffer`, `fs_shadow` | `horizon/crates/horizon-client/src/terrain.wgsl` | | G-буфер сущностей и моделей мода: `fs_entity_gbuffer`, `fs_entity_shadow` | `horizon/crates/horizon-client/src/entity.wgsl` | | Пост-проход мода (взрывы, дым, вспышки, свечение) и его прелюдия | `airdef-mod/shaders/effects.wgsl`, прелюдия в `horizon/.../gfx/mod_post.rs` | | Источники света мода (пламя, ракеты, взрывы, прожекторы) | `airdef-mod/src/lib.rs`, `fn lights` | | API мода: `render.set-lights`, `render.set-lighting` (уровень API 10) | `horizon/crates/horizon-mod-sdk/wit/horizon.wit`, `horizon/crates/horizon-mods/src/runtime.rs` | Форк ведётся в `horizon/` (ветка `airdef`), в репозиторий мода попадает **патчами**: ```bash cd horizon && git add -A crates && git commit -m "..." # коммит в форке cd .. && rm -f horizon-patches/*.patch && git -C horizon format-patch -q $(cat HORIZON_COMMIT)..airdef -o ../horizon-patches ``` `tools/airdef.py fork` сверяет отпечаток `HORIZON_COMMIT` + патчей (`horizon/.git/airdef-stamp`) и пересобирает ветку, если они изменились. После ручной перегенерации патчей у себя обнови отпечаток (см. `fork_stamp` в `tools/airdef.py`), иначе следующий `airdef.py fork` пересоберёт ветку (безопасно: прежняя остаётся в `airdef-prev`). ## Конвейер кадра (HD включён) Все цели в «масштабированном» разрешении мира (`world_post`), HDR — `Rgba16Float`. Глубина камеры — reversed-Z (`Depth32Float`, 1 = близко, 0 = далеко). Позиции везде относительно камеры (camera-relative), мир — в `f64` на CPU. 1. **Каскады теней** (2 шт., `CASCADES = [40, 176]` блоков полуразмера, `SHADOW_SIZE = 2048`, массив глубины из 2 слоёв). Источник — солнце днём, луна ночью (`light_of`). Матрицы `cascades()` привязаны к текселям (тени не «ползут»). Во время прохода буфер глобалов мира подменяется на глобалы каскада (copy-трюк) и потом возвращается. Рисуются секции террейна в коробке дальнего каскада (`hd_shadow_visible`) и сущности-тенеотбрасыватели (`shadow_casters`: без оверлеев 4/9/10/40 — 40 это светящиеся модели мода). 2. **G-буфер** (свой depth): albedo `Rgba8Unorm` (a = эмиссия), нормаль `Rgba16Float` (мировая, из `dpdx/dpdy`), уровни света `Rgba8Unorm` (x = небо, y = блоки — сырые координаты лайтмапа /240). Террейн + дальние LOD-тайлы + сущности. Вода/полупрозрачное в G-буфер **не** попадает (идёт ванильным путём) — см. план. 3. **GTAO** (полразрешения, `Rg16Float`: окклюзия, дистанция) + depth-aware блюр 5×5. 3 среза × 5 шагов, радиус 1.8 блока, шум IGN по кадру. Сила — `HdFrame.ambient.w` (`HORIZON_HD_AO=<число>`, 0 = выкл). 4. **Освещение** `fs_light` → `lit` (HDR): `max(небо·ambient.x, блоки·ambient.y)·AO + солнце·N·L·тень + точечные источники` × albedo + эмиссия; затем ванильный туман заново, объёмные лучи (14 шагов, Henyey-Greenstein g=0.6), ореолы вокруг источников. Точечные источники — по тайлам 16×16 (`tile_lists`, буфер `tiles`: на тайл 4 слова — начало/длина списка для поверхностей и для ореолов, потом индексы; переполнение → «все источники»). 5. **Пост-проход мода** `lit` → `fx` (`effects.wgsl`: взрывы, дым, вспышки, свечение; при HD его собственная «подсветка огнём» выключена — свет даёт HD). 6. **TAA** — после пост-прохода мода (`fx`, либо `lit` без него), до bloom: история пинг-понгом, в альфе истории — дистанция для отбраковки дизокклюзии; телепорт > 64 блоков сбрасывает историю. Джиттер добавляется к `view_projection` только при HD (публичная матрица без джиттера); рука и HUD рисуются после tonemap и не дрожат. 7. **Bloom** (prefilter + 6 уровней: 13-tap вниз, tent вверх) и **tonemap**: до 0.8 как есть (ванильный вид), выше — мягкий roll-off по ярчайшему каналу; лёгкий грейд (+12% насыщенности, мягкая S-кривая). Bind groups кэшируются и пересоздаются только при resize/смене источника (`hd_bind_groups_last_frame()` → 0 в установившемся режиме). ### Привязки `fs_light` (group 0) | # | Что | |---|---| | 0 | `HdFrame` (uniform) | | 1, 2 | цвет и глубина мира (ванильный проход) | | 3, 4, 5 | albedo, нормаль, глубина G-буфера | | 6 | источники света (storage, `HdLight`: pos+radius, color+intensity) | | 7 | уровни света (небо, блоки) | | 8, 9 | массив карт теней, comparison-сэмплер | | 10, 11 | лайтмап, линейный сэмплер | | 12 | тайлы источников (storage) | | 13 | AO | `HdFrame` (Rust и WGSL держать в синхроне!): `inverse_view_proj`, `resolution` (w, h, 1/w, 1/h), `params` (число источников, экспозиция, bloom, счётчик кадров), `cascades[2]`, `sun` (направление, сила), `sun_color` (rgb, ночь), `fog_color`, `fog`, `ambient` (тень неба, блоки, плотность воздуха, AO), `shadow` (вкл, R0, R1, тайлов в строке). ## Как проверять ```bash cd horizon && cargo build --profile fast -p horizon-client --features mods # без предупреждений cargo fmt -p horizon-client cargo test -p horizon-client --lib hd # naga-разбор всех HD-шейдеров + тест тайлов cd ../airdef-mod && cargo horizon-mod build && cargo test # мод и его шейдер ``` WGSL-ошибки в `hd.rs` всплывают только в рантайме — поэтому каждый новый шейдер добавляй в naga-тест `lighting_shader_parses`. Игра офскрин (только одна копия за раз; данные в `run-home/`, мир `Polygon`): ```bash cd run-home && HORIZON_HOME=$PWD HORIZON_NO_AUDIO=1 ../horizon/target/fast/horizon-ctl --socket $PWD/ctl.sock \ launch --world Polygon --offscreen --wait --game ../horizon/target/fast/horizon-client \ --resources "$(ls -d "$HOME/Library/Application Support/horizon-launcher/versions"/*/.local/horizon-client/26.3 | sort -V | tail -1)" H="../horizon/target/fast/horizon-ctl --socket $PWD/ctl.sock" $H command "time set 4500"; $H command "tp @s 40 76 40 135 25" # полигон с техникой; z ≥ 60 — море # команды мода — через чат: $H key t tap; $H type "/airdef shader hd"; $H key return tap $H key f1 tap; $H screenshot out.png; $H bench 4; $H quit ``` Тайминги проходов на GPU: `HORIZON_SHADER_PACK_TIMING=1` (лог в `run-home/ctl.log`) или список F3. Ориентиры (M5, 2560×1440): тени 0.6 + 2.85 мс (дальний каскад через кадр, ≈1.4 в среднем), G-буфер 0.8, AO 2.9, освещение 5.2, TAA 2.7, bloom 1.1, tonemap 0.2 — кадр ≈ 15 мс GPU (замеры шумные). Следующие цели по скорости: освещение (лучи 14 шагов на полном разрешении → полразрешения + апскейл) и AO. Отладка: временно выводи промежуточные величины цветом в `fs_light` (так нашли пустую карту теней и неверное направление солнца). Помни: солнце в мире идёт по оси X (`(-sin a, cos a, 0)`), а `Globals.sun` неба — в своей плоскости YZ. ## Статус | Этап | Состояние | Коммит | |---|---|---| | 1. G-буфер, точечный свет мода в HDR, bloom, тон-кривая; API `set-lights`/`set-lighting` | готово | 0a56f56 (форк) | | 2. Тени солнца/луны, переосвещение мира, лучи, ореолы, туман, грейд | готово | патч 12 | | Кэш bind groups, тени только от тенеотбрасывателей (#12, #13) | готово | патч 13 | | Тайловые списки источников (#10) | готово | патч 14 | | Тайминги HD-проходов (#9), GTAO | готово | патч 15, ed2db85 | | Отсечение взрывов в `effects.wgsl` (#11), порядок дыма (#16), метрика перекрытия свечения (#14) | готово | 67a2a52, ed2db85 | | Тени: только грани к солнцу, без «закопанных» секций, дальний каскад через кадр (`HORIZON_HD_SHADOW_FAST=0` — по-старому) | готово | патч 16 | | TAA: джиттер Halton(2,3) ×16, перепроекция по глубине и сдвигу камеры, variance clip в YCoCg, история Catmull-Rom 0.9, лёгкий шарп в tonemap (`HORIZON_HD_TAA=0` — выкл) | готово | патч 16 | | API моделей по хэндлам (#30, уровень API 11: `model-id`, `model-generation`, `set-models-by-id`) | готово | патч 17 | ## План (по порядку) и ТЗ Каждый пункт — самостоятельная задача. Перед началом прочитай `hd.rs` целиком. 1. **TAAU — временной апскейлер** (поверх TAA). Мир и G-буфер рендерятся в `render_scale` (например 0.67), TAA-проход восстанавливает полное разрешение: история в полном разрешении, текущий кадр семплируется с учётом джиттера (Catmull-Rom/Lanczos-веса по субпиксельной позиции), клиппинг окрестности как в TAA. Настройка масштаба (`HORIZON_HD_SCALE` или поле в `HdSettings`). Цель: при 0.67 картинка близка к нативной, FPS заметно выше. Альтернатива на Mac — MetalFX через wgpu-hal (нативный код, только Metal) — отдельной опцией потом. DLSS нереален для нашей цели (только NVIDIA через Streamline, нет в wgpu). 2. **Вода**: отдельный G-буфер-путь для воды (маска + нормаль с анимированными волнами), SSR (трассировка по глубине, откат на небо/туман), преломление (смещение по нормали), затухание по глубине воды (цвет биома), блики солнца (GGX-подобный), френель. Подводный вид не ломать (`frame.underwater`). 3. **Небо и атмосфера**: рассеяние Рэлея/Ми (предвычисленная LUT пропускания и небесного цвета в маленькой текстуре), солнце/луна дисками, звёзды из ванили; туман и лучи берут цвет из той же модели. Учесть дождь (`weather`), закат, Незер/Энд (там — ванильное небо). 4. **Объёмные облака** (рэймарч слоя с шумом) + их тени на земле (в карту/маску солнца). 5. **Блики и материалы**: specular солнца для металла техники (маска по оверлею/альбедо или атрибут модели из мода), мокрые поверхности и лужи в дождь. 6. **PCSS** (мягкость тени по расстоянию до тенеотбрасывателя) и цветные тени через стекло/листву. 7. **Ветер** листвы/травы (вершинный шейдер террейна по типу блока), рябь от дождя. 8. **Объёмный дым** пожаров и взрывов, принимающий свет и тени (сейчас дым — в `effects.wgsl`, без теней). 9. Опционально: motion blur, DoF (для кинокамеры повторов). 10. **RT-пресет**: `wgpu` `EXPERIMENTAL_RAY_QUERY` (Vulkan/DX12/Metal M3+), BLAS по секциям, ray-query тени и отражения, затем GI. Отдельный пресет, HD остаётся. ## Правила - Ничего не ломать в `off`/`on`; HD выключен — код HD не работает вовсе (`hd = None`). - Без потери качества ради скорости без договорённости (шаги, разрешение, число эффектов). - Каждый новый WGSL — в naga-тест. Каждый новый проход — в тайминги (`PassTiming`). - Комментарии — короткие предложения о том «зачем»; в `gfx.rs` префикс `AirDef fork:`. - Коммиты: в форке, затем патчи; подпись `Co-Authored-By: Claude <модель> `. - Пуш в Gitea с машины без DNS: `ssh://git@100.92.6.40:2222/chexit/airdef.git` (ключ `~/Documents/claude-keys/deploy`). - Обнови этот документ (статус + что изменилось в конвейере) в том же коммите, что и код.