Files
airdef/docs/HD-RENDERER.md
T
chexit 65dd84646a
build / mod (push) Successful in 3m20s
docs: HD renderer architecture, status and plan, kept up to date for handover
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 16:55:15 +03:00

167 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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** (в работе, см. статус) — после пост-прохода мода.
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, до оптимизации теней): тени 1.3 + 5.4 мс, G-буфер 0.8, AO 2.9, освещение 5.2,
bloom 1.1, tonemap 0.2 — кадр ≈ 17 мс GPU.
Отладка: временно выводи промежуточные величины цветом в `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 |
| Удешевление дальнего каскада теней | в работе | — |
| TAA (джиттер Halton 2,3, перепроекция по глубине, клиппинг в YCoCg) | в работе | — |
## План (по порядку) и ТЗ
Каждый пункт — самостоятельная задача. Перед началом прочитай `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 <модель> <noreply@anthropic.com>`.
- Пуш в Gitea с машины без DNS: `ssh://git@100.92.6.40:2222/chexit/airdef.git` (ключ `~/Documents/claude-keys/deploy`).
- Обнови этот документ (статус + что изменилось в конвейере) в том же коммите, что и код.