Compare commits

..

2 Commits

Author SHA1 Message Date
chexit 51f9609327 Distinct item icons: a silhouette per item and category instead of one remote (#99)
build / mod (push) Successful in 3m50s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 15:07:54 +03:00
chexit 3265eb63d2 HD: coloured shadows, rain ripples, film motion blur and depth of field (fork patch 34)
build / mod (push) Successful in 3m46s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 15:01:09 +03:00
65 changed files with 1486 additions and 51 deletions
Binary file not shown.

Before

Width:  |  Height:  |  Size: 404 B

After

Width:  |  Height:  |  Size: 265 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 397 B

After

Width:  |  Height:  |  Size: 336 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 400 B

After

Width:  |  Height:  |  Size: 241 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 396 B

After

Width:  |  Height:  |  Size: 278 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 400 B

After

Width:  |  Height:  |  Size: 297 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 388 B

After

Width:  |  Height:  |  Size: 249 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 395 B

After

Width:  |  Height:  |  Size: 297 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 386 B

After

Width:  |  Height:  |  Size: 286 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 402 B

After

Width:  |  Height:  |  Size: 307 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 397 B

After

Width:  |  Height:  |  Size: 285 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 403 B

After

Width:  |  Height:  |  Size: 314 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 399 B

After

Width:  |  Height:  |  Size: 243 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 407 B

After

Width:  |  Height:  |  Size: 409 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 401 B

After

Width:  |  Height:  |  Size: 338 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 400 B

After

Width:  |  Height:  |  Size: 316 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 392 B

After

Width:  |  Height:  |  Size: 154 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 386 B

After

Width:  |  Height:  |  Size: 139 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 393 B

After

Width:  |  Height:  |  Size: 223 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 404 B

After

Width:  |  Height:  |  Size: 210 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 403 B

After

Width:  |  Height:  |  Size: 233 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 408 B

After

Width:  |  Height:  |  Size: 184 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 409 B

After

Width:  |  Height:  |  Size: 254 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 393 B

After

Width:  |  Height:  |  Size: 151 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 392 B

After

Width:  |  Height:  |  Size: 149 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 397 B

After

Width:  |  Height:  |  Size: 269 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 408 B

After

Width:  |  Height:  |  Size: 243 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 394 B

After

Width:  |  Height:  |  Size: 128 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 404 B

After

Width:  |  Height:  |  Size: 464 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 411 B

After

Width:  |  Height:  |  Size: 257 B

+13 -3
View File
@@ -233,6 +233,9 @@ HORIZON_HD_TAA=0 --out run-home-bench/out/taa-off` — A/B; `--baseline run-home
| #68: шум облаков по Y — от низа слоя, а не от камеры; шкалы тумана 170→128, дыма 22→32, луж 0.45/1.3→0.5/1.25 делят период обёртки 65536/256; тест `noise_scales_divide_the_camera_wrap` | готово | в рабочем дереве форка |
| #70: `Game::sky_darken` — всегда реальное время мира (ИИ, спавн, блоки, статистика); `shown_sky_darken` (время реплея) — только тени сущностей и свет глаза; небо/луна/цвета остаются по показанному времени | готово (собрано, игровой проверки день/ночь реплея нет) | в рабочем дереве форка |
| Объёмный дым и следы ракет (#54, п. 8 плана): API уровня 14 `render.set-smoke`, сетка дыма 128×64×128 по 3 блока (`gfx/hd/smoke.rs`, `smoke_grid.wgsl`), марш в проходе тумана, «туннель» в тумане и облаках, `HORIZON_HD_SMOKE=0`; мод: `airdef-mod/src/smoke.rs` (следы дронов и ракет, колонны над пожарами, дым взрывов) | готово, в рабочем дереве форка; вид не настраивался (см. «Дым и следы») | не закоммичено |
| Цветные тени (план 6): ближний каскад без листвы в глубине + карта цвета 1024² (`Rgba16Float`, `shadow_tint_pass`): стекло/лёд умножают свет на цвет, листва пропускает ×0.55 зелёного; в альфе расстояние до источника света (min-blend); `fs_light` берёт 8 отсчётов (`shadow_tint`); `HORIZON_HD_COLOR_SHADOW=0` — выкл. | готово; радуга от цветного стекла видна в игре, листва — слабым зеленоватым пятном; без A/B с выключенным | в рабочем дереве форка |
| Рябь от дождя на воде (остаток плана 7): кольца в сетке 1.6 блока (`ripple_gradient`, `water.wgsl`), уровень дождя в `sky_extra.w`; `HORIZON_HD_RAIN_RIPPLES=0` — выкл. | готово; в игре едва различимы дуги в бликах (частицы дождя закрывают), не настраивалось | в рабочем дереве форка |
| Motion blur и DoF кинокамеры (план 9): `gfx/hd/film.rs` + `film.wgsl`, проход после TAA, только при `film_quality()`; `HORIZON_HD_MOTION_BLUR=0`, `HORIZON_HD_DOF=0`, `HORIZON_HD_DOF_FOCUS`, `HORIZON_HD_DOF_STRENGTH`, `HORIZON_HD_FILM_QUALITY=1` (принудительно, для проб) | DoF виден в игре (до правки стоил 14–17 мс); motion blur в игре не подтверждён; правка стоимости DoF (планарная глубина, 24 отсчёта, радиус 0.7%) собрана и прошла тесты, но глазами не проверена | в рабочем дереве форка |
## План (по порядку) и ТЗ
@@ -253,10 +256,10 @@ HORIZON_HD_TAA=0 --out run-home-bench/out/taa-off` — A/B; `--baseline run-home
4. **Объёмные облака** — СДЕЛАНО (патч 24, см. «Закат, облака и туман»). Перистые и облака в воде сделаны (см. «Облака, перистые, туман по рельефу»).
5. **Блики и материалы** — СДЕЛАНО (см. «Материалы, мокрое, ветер»). Исходное ТЗ: specular солнца для металла техники (маска по оверлею/альбедо или атрибут модели из
мода), мокрые поверхности и лужи в дождь.
6. **PCSS** (мягкость тени по расстоянию до тенеотбрасывателя) и цветные тени через стекло/листву.
7. **Ветер** — СДЕЛАНО (рябь от дождя на воде осталась). Исходное ТЗ: листвы/травы (вершинный шейдер террейна по типу блока), рябь от дождя.
6. **PCSS** и цветные тени через стекло/листву — СДЕЛАНО (см. «Цветные тени, рябь, кино-пост»). Не сделано: цвет в лучах тумана и в тени под водой, цветная тень дальнего каскада.
7. **Ветер** и рябь от дождя — СДЕЛАНО. Исходное ТЗ: листвы/травы (вершинный шейдер террейна по типу блока), рябь от дождя.
8. **Объёмный дым** пожаров и взрывов, принимающий свет и тени (сейчас дым — в `effects.wgsl`, без теней).
9. Опционально: motion blur, DoF (для кинокамеры повторов).
9. Motion blur, DoF для кинокамеры — СДЕЛАНО в коде (см. ниже), проверено частично.
10. **RT-пресет**: `wgpu` `EXPERIMENTAL_RAY_QUERY` (Vulkan/DX12/Metal M3+), BLAS по секциям, ray-query тени и
отражения, затем GI. Отдельный пресет, HD остаётся.
@@ -364,3 +367,10 @@ HORIZON_HD_TAA=0 --out run-home-bench/out/taa-off` — A/B; `--baseline run-home
- **Захват** (`render.capture-start/stop/status`, `game/film.rs`, `Renderer::capture_*`): часы игры идут ровно `1/fps` секунды за кадр (тики, интерполяция, `tick` мода), кадр копируется с GPU через очередь из ≤3 буферов и уходит в поток-писатель → `ffmpeg` (libx264, иначе h264_videotoolbox; иначе PNG-последовательность). Звук: микшер OpenAL-подобный (`audio.rs`) работает офлайн (`film_begin/film_mix`), слышны только звуки мода, ориентация — по камере; дорожка вмуксивается AAC. После склейки рисуются `warmup` кадров без записи, чтобы сошлись TAA и объёмы. Размер: offscreen-игра ресайзится, окно просится (`request_inner_size`).
- Мод-HUD (`set-hud`) теперь рисуется и при `set-main-view` (титры, леттербокс фильма); ванильный HUD по-прежнему скрыт.
- Режиссура: `airdef-mod/src/film.rs` (план по записи, варианты ракурсов, проверка рельефа по высотам `Ground::land_state`, ускорение/замедление времени).
## Цветные тени, рябь, кино-пост: что знать преемнику
- **Цветные тени.** Ближний каскад (c = 0) рисуется `fs_shadow_near` (листва `MAT_LEAVES` отброшена), потом проход `hd shadow colour` (`Hd::shadow_tint_pass`, цель `Shadows::tint`, очистка в белое) рисует листву (`shadow_tint_leaves`, твёрдые квады, `SHADOW_SOLID`) и полупрозрачные квады секций (`shadow_tint_glass`, по отсортированным индексам; вода не рисуется) тем же `fs_shadow_tint`: rgb умножаются (blend `Dst*src`), альфа = `(расстояние от света − 320)/160` с blend Min — ближайший такой квад. Приёмник в `shadow_tint` (`light.wgsl`, привязка 22) окрашивается, если квад ближе к свету, чем он; 8 точек Vogel радиусом 0.4 блока размывают листву в «пятна». Дальний каскад по-прежнему рисует листву полностью (на границе 36 блоков шов: ближе листва светлее). Цвет не доходит до лучей тумана, воды и дальнего каскада. Цена: `hd shadow colour` 0.25–0.35 мс (Mac, малая сцена).
- **Рябь.** `ripple_gradient` берёт часы воды (`water.y`, часы фильма): частоты — целые циклы на 600 с, сетка 160 клеток на 256 блоков, поэтому рисунок не прыгает на обороте. Гаснет по размеру пикселя, только под открытым небом (`nt.a`). Амплитуда 0.012 не подбиралась.
- **Кино-пост.** `Hd::film` между `taa` и `finish` (`HdSource::Film`), только при `film_quality()`; цели создаются при первом фильме. Motion blur — только от движения камеры (глубина + `prev_view_proj`, затвор 180°, мёртвая зона 1–2.5 px из-за джиттера; движущиеся объекты не размываются; нет после склейки/телепорта: `taa.w`). DoF — диск 24 отсчёта, фокус авто (гармоническое среднее 9 глубин у центра) или `HORIZON_HD_DOF_FOCUS`. Детерминизм: единственное время в шейдере — `water.y` (часы фильма) для шума. Проверять на реальном фильме `/airdef replay film`; `HORIZON_HD_FILM_QUALITY=1` принудительно включает качество фильма для проб. DoF в игре был слишком сильным и дорогим; параметры уменьшены без повторного снимка. Motion blur на снимке (поворот 40° за 1.5 с) не разобран.
- Из Photon (MIT) ничего нового не переносилось: THIRD_PARTY_PHOTON.md не менялся.
@@ -1,7 +1,7 @@
From 3de7a6875140a107e28563cc44489b55f5794517 Mon Sep 17 00:00:00 2001
From: chexit <chexit@duck.com>
Date: Wed, 28 Oct 2026 12:37:45 +0300
Subject: [PATCH 01/33] Mod API (AirDef fork): world models, client particles,
Subject: [PATCH 01/34] Mod API (AirDef fork): world models, client particles,
sounds, ground heights
render.set-models draws block models with an interpolated pose per id;
@@ -1,7 +1,7 @@
From a6d64e6415bf618539af464e521091e72b72d72f Mon Sep 17 00:00:00 2001
From: chexit <chexit@duck.com>
Date: Wed, 28 Oct 2026 12:39:45 +0300
Subject: [PATCH 02/33] cargo-horizon-mod: report particles and sounds
Subject: [PATCH 02/34] cargo-horizon-mod: report particles and sounds
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---
@@ -1,7 +1,7 @@
From ee79b3562feebe51959a01f1585a9e85bd53ccb5 Mon Sep 17 00:00:00 2001
From: chexit <chexit@duck.com>
Date: Wed, 28 Oct 2026 13:33:10 +0300
Subject: [PATCH 03/33] Mod API (AirDef fork): full-screen post pass for mods
Subject: [PATCH 03/34] Mod API (AirDef fork): full-screen post pass for mods
render.set-post compiles a mod's WGSL after a prelude (camera matrices,
time, 256 vec4 of params, the world's colour and depth) and runs it after
@@ -1,7 +1,7 @@
From 2b137dbbedd540daeebc7f5e387847aeb56a1355 Mon Sep 17 00:00:00 2001
From: chexit <chexit@duck.com>
Date: Wed, 28 Oct 2026 22:09:30 +0300
Subject: [PATCH 04/33] Mod models: draw far models as scaled impostors past
Subject: [PATCH 04/34] Mod models: draw far models as scaled impostors past
the far plane, cull at 4096
---
@@ -1,7 +1,7 @@
From c8ebca6e0af68630e65211844b34d25c5b985c03 Mon Sep 17 00:00:00 2001
From: chexit <chexit@duck.com>
Date: Wed, 28 Oct 2026 22:31:00 +0300
Subject: [PATCH 05/33] Mod cameras: render.set-views draws the world from
Subject: [PATCH 05/34] Mod cameras: render.set-views draws the world from
other points into pictures that HUD view shapes show (API level 9)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@@ -1,7 +1,7 @@
From 8d2261fc4f8072c32e454139cfea7a8c0cd9d664 Mon Sep 17 00:00:00 2001
From: chexit <chexit@duck.com>
Date: Wed, 28 Oct 2026 23:08:21 +0300
Subject: [PATCH 06/33] Mods: more fuel per tick and per event (AirDef plans
Subject: [PATCH 06/34] Mods: more fuel per tick and per event (AirDef plans
raids)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@@ -1,7 +1,7 @@
From 6c548de34def8e4a624d734243418090798bd16a Mon Sep 17 00:00:00 2001
From: chexit <chexit@duck.com>
Date: Wed, 28 Oct 2026 23:25:29 +0300
Subject: [PATCH 07/33] Mod cameras up to 1920x1080 (full-screen replays)
Subject: [PATCH 07/34] Mod cameras up to 1920x1080 (full-screen replays)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---
@@ -1,7 +1,7 @@
From 9b9e93269d67401cc620567a884d5ce97f68d76e Mon Sep 17 00:00:00 2001
From: chexit <chexit@duck.com>
Date: Thu, 29 Oct 2026 11:15:11 +0300
Subject: [PATCH 08/33] Mod cameras: distant terrain tiles, fog measured from
Subject: [PATCH 08/34] Mod cameras: distant terrain tiles, fog measured from
the camera, no impostors while one is shown
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@@ -1,7 +1,7 @@
From 065d9fa02966238a5bd9ff460392a1a809db0b11 Mon Sep 17 00:00:00 2001
From: chexit <chexit@duck.com>
Date: Thu, 29 Oct 2026 11:25:45 +0300
Subject: [PATCH 09/33] Mods: game.world-id, so mods keep state per world (API
Subject: [PATCH 09/34] Mods: game.world-id, so mods keep state per world (API
level 9)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@@ -1,7 +1,7 @@
From 1bf28135fd9a31f837323dc3a8d81ed73343d816 Mon Sep 17 00:00:00 2001
From: chexit <chexit@duck.com>
Date: Thu, 29 Oct 2026 12:01:08 +0300
Subject: [PATCH 10/33] cargo-horizon-mod: trial runs behind feature full, so a
Subject: [PATCH 10/34] cargo-horizon-mod: trial runs behind feature full, so a
packing-only tool skips wasmtime
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@@ -1,7 +1,7 @@
From 0a56f5616df4699588cbcc529d4720661baa810f Mon Sep 17 00:00:00 2001
From: chexit <chexit@duck.com>
Date: Thu, 29 Oct 2026 13:18:43 +0300
Subject: [PATCH 11/33] HD lighting: G-buffer pass, per-pixel mod point lights
Subject: [PATCH 11/34] HD lighting: G-buffer pass, per-pixel mod point lights
in HDR, bloom and tone curve; render.set-lights and render.set-lighting (API
level 10)
@@ -1,7 +1,7 @@
From 9ebf0031fe9ba6b7f02afb26e4fd3a1ba4ddb0d0 Mon Sep 17 00:00:00 2001
From: chexit <chexit@duck.com>
Date: Thu, 29 Oct 2026 13:59:43 +0300
Subject: [PATCH 12/33] HD lighting stage 2: sun and moon shadow cascades, the
Subject: [PATCH 12/34] HD lighting stage 2: sun and moon shadow cascades, the
world relit (sun by face angle and shadow, sky and block light through the
lightmap), light shafts and halos, fog over it again, a light colour grade
@@ -1,7 +1,7 @@
From 7a5a38f68923aec62f10bfa0df50b436474ed612 Mon Sep 17 00:00:00 2001
From: chexit <chexit@duck.com>
Date: Thu, 29 Oct 2026 16:19:53 +0300
Subject: [PATCH 13/33] HD: bind groups cached until a resize or a new source,
Subject: [PATCH 13/34] HD: bind groups cached until a resize or a new source,
shadow passes draw only the entities that cast shadows
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@@ -1,7 +1,7 @@
From 8020811e57d4b5a9ea1cd72d30ce859dc5095d35 Mon Sep 17 00:00:00 2001
From: chexit <chexit@duck.com>
Date: Thu, 29 Oct 2026 16:25:44 +0300
Subject: [PATCH 14/33] HD: lights culled per 16x16 tile (surface and halo
Subject: [PATCH 14/34] HD: lights culled per 16x16 tile (surface and halo
lists built on the CPU), a naga test for the lighting shaders
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@@ -1,7 +1,7 @@
From 72d3fddfea329e578162656151350f0aa2efd323 Mon Sep 17 00:00:00 2001
From: chexit <chexit@duck.com>
Date: Thu, 29 Oct 2026 16:43:36 +0300
Subject: [PATCH 15/33] HD: GPU time per pass in the F3 timing list,
Subject: [PATCH 15/34] HD: GPU time per pass in the F3 timing list,
half-resolution GTAO with a depth-aware blur
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@@ -1,7 +1,7 @@
From 1fd83a821bf270879d8ece5aa583f200ed920d89 Mon Sep 17 00:00:00 2001
From: chexit <chexit@duck.com>
Date: Thu, 29 Oct 2026 17:02:02 +0300
Subject: [PATCH 16/33] HD: shadows draw only sun-facing quads and skip buried
Subject: [PATCH 16/34] HD: shadows draw only sun-facing quads and skip buried
sections, the far cascade every second frame; TAA (Halton jitter,
reprojection by depth, YCoCg variance clipping) before bloom
@@ -1,7 +1,7 @@
From 1502d359d599228fe0f44ce6b99a3fded2ac5ea0 Mon Sep 17 00:00:00 2001
From: chexit <chexit@duck.com>
Date: Thu, 29 Oct 2026 17:02:02 +0300
Subject: [PATCH 17/33] Mods: model handles (render.model-id, model-generation,
Subject: [PATCH 17/34] Mods: model handles (render.model-id, model-generation,
set-models-by-id; API level 11) so mods send no model names each tick;
clear-post and set-lighting documented
@@ -1,7 +1,7 @@
From 0f9d99b8ad3e4b72e621d84c2396cf1d3d2b7a33 Mon Sep 17 00:00:00 2001
From: chexit <chexit@duck.com>
Date: Thu, 29 Oct 2026 17:19:57 +0300
Subject: [PATCH 18/33] HD: temporal upscaling (HORIZON_HD_SCALE: world,
Subject: [PATCH 18/34] HD: temporal upscaling (HORIZON_HD_SCALE: world,
G-buffer and lighting at a lower size, rebuilt to the window in the TAA
pass); fix flickering shadows near the player (the near cascade lost its
sections on frames the far one was held, the held far matrix ignored the
@@ -1,7 +1,7 @@
From 38250c4392e27d5700842ca6ee47291dd1831b72 Mon Sep 17 00:00:00 2001
From: chexit <chexit@duck.com>
Date: Thu, 29 Oct 2026 17:47:52 +0300
Subject: [PATCH 19/33] HD water: its own pass (colour, normal, depth), the
Subject: [PATCH 19/34] HD water: its own pass (colour, normal, depth), the
floor under it lit, a composite with world-space waves, refraction with depth
absorption in the biome colour, screen-space reflections, Fresnel and a
shadowed sun glint (HORIZON_HD_WATER=0 to switch off)
@@ -1,7 +1,7 @@
From dbc6f8a6e9c2eeabe1de15f1794013c90be7faa5 Mon Sep 17 00:00:00 2001
From: chexit <chexit@duck.com>
Date: Thu, 29 Oct 2026 17:56:04 +0300
Subject: [PATCH 20/33] HD water: no vanilla texture on the surface (the biome
Subject: [PATCH 20/34] HD water: no vanilla texture on the surface (the biome
colour only), a darker, deeper colour
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@@ -1,7 +1,7 @@
From 13e74537dd6e63482e3613e0e416de1158944dfe Mon Sep 17 00:00:00 2001
From: chexit <chexit@duck.com>
Date: Thu, 29 Oct 2026 18:38:19 +0300
Subject: [PATCH 21/33] HD sky and light: a physical atmosphere (Rayleigh, Mie,
Subject: [PATCH 21/34] HD sky and light: a physical atmosphere (Rayleigh, Mie,
ozone; constants and transmittance after Photon, MIT) for the sky, haze, fog
and water reflections; warmer sunlight from the atmosphere's transmittance, a
gentle sky-coloured ambient, soft PCSS-lite shadows near the player, a haze
@@ -1,7 +1,7 @@
From 6277e051a89c2537570982f6ef275887193c05cf Mon Sep 17 00:00:00 2001
From: chexit <chexit@duck.com>
Date: Thu, 29 Oct 2026 19:02:16 +0300
Subject: [PATCH 22/33] HD water: a darker blue, a little clearer, ripples a
Subject: [PATCH 22/34] HD water: a darker blue, a little clearer, ripples a
little higher
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@@ -1,7 +1,7 @@
From 982265d21bb9d74ec0040db03feb5a55762286ad Mon Sep 17 00:00:00 2001
From: chexit <chexit@duck.com>
Date: Thu, 29 Oct 2026 21:41:48 +0300
Subject: [PATCH 23/33] HD: Photon-style sunsets (Rec. 2020 atmosphere, sun
Subject: [PATCH 23/34] HD: Photon-style sunsets (Rec. 2020 atmosphere, sun
tint, blue hour; MIT), volumetric clouds with ground shadows instead of
vanilla's in HD, volumetric fog with sun shafts and morning mist
(HORIZON_HD_CLOUDS=0, HORIZON_HD_VOLFOG=0)
@@ -1,7 +1,7 @@
From 24971b3c67d8c87673eb2e0d204cedf8a2f46d1c Mon Sep 17 00:00:00 2001
From: chexit <chexit@duck.com>
Date: Thu, 29 Oct 2026 21:43:22 +0300
Subject: [PATCH 24/33] Mods: world queries for simulations (render.query-rays,
Subject: [PATCH 24/34] Mods: world queries for simulations (render.query-rays,
query-sections, world-changes; API level 12): block-exact rays and section
occupancy by collision, sight or sound, answered next tick within budgets,
and a log of changed sections
@@ -1,7 +1,7 @@
From fdec4960983bdff82f3793460f9a5234f0cd3f49 Mon Sep 17 00:00:00 2001
From: chexit <chexit@duck.com>
Date: Thu, 29 Oct 2026 22:56:15 +0300
Subject: [PATCH 25/33] HD fixes: rain level from the world not from rain
Subject: [PATCH 25/34] HD fixes: rain level from the world not from rain
geometry (#41), TAA history on the jittered grid (#38), vanilla cloud tint
without a depth heuristic (#35), air fog once over water (#37), translucent
things in front of HD water (#36), cheaper sunrise fan (#39), halos in thick
@@ -1,7 +1,7 @@
From 21391afb26f49505d6cdaf454a6355cd4e747503 Mon Sep 17 00:00:00 2001
From: chexit <chexit@duck.com>
Date: Thu, 29 Oct 2026 23:19:53 +0300
Subject: [PATCH 26/33] HD split into modules (gfx/hd/: one Rust file and one
Subject: [PATCH 26/34] HD split into modules (gfx/hd/: one Rust file and one
WGSL file per pass, a shared prelude), contracts for colour, depth, alpha,
time and coordinates written down, tests that the frame layout and bindings
match between Rust and WGSL (#45)
@@ -1,7 +1,7 @@
From 8d4cadbf8534309ac847d34e229f6d764770475d Mon Sep 17 00:00:00 2001
From: chexit <chexit@duck.com>
Date: Thu, 29 Oct 2026 23:22:19 +0300
Subject: [PATCH 27/33] HD clouds: noise scales that divide the camera's
Subject: [PATCH 27/34] HD clouds: noise scales that divide the camera's
65536-block wrap, so the clouds and their shadows no longer jump at x or z =
0
@@ -1,7 +1,7 @@
From 0fb59c782abf269fe555faa3241b31acf41e26d7 Mon Sep 17 00:00:00 2001
From: chexit <chexit@duck.com>
Date: Fri, 30 Oct 2026 03:17:11 +0300
Subject: [PATCH 28/33] HD: volumetric smoke and missile trails with clear
Subject: [PATCH 28/34] HD: volumetric smoke and missile trails with clear
tunnels through fog and cloud (render.set-smoke, API level 14; #54); sun
speculars by material, wet surfaces and puddles in rain, wind in foliage
(HORIZON_HD_SPECULAR=0, HORIZON_HD_WIND=0, HORIZON_HD_SMOKE=0); HD shaders
@@ -1,7 +1,7 @@
From e4bc29da45d0d38244c6eb2ba3ffb9ab853540c0 Mon Sep 17 00:00:00 2001
From: chexit <chexit@duck.com>
Date: Fri, 30 Oct 2026 03:26:09 +0300
Subject: [PATCH 29/33] HD clouds composited by depth so terrain and vehicles
Subject: [PATCH 29/34] HD clouds composited by depth so terrain and vehicles
inside or behind the layer are hidden and those in front stay in front (#67);
world-anchored noise everywhere (cloud detail by height above the layer, fog,
smoke and puddle scales dividing the wrap) (#68); the replay's time is visual
@@ -1,7 +1,7 @@
From 20f699796afb12b600236a4e8859cd97430f86f0 Mon Sep 17 00:00:00 2001
From: chexit <chexit@duck.com>
Date: Fri, 30 Oct 2026 03:44:45 +0300
Subject: [PATCH 30/33] HD smoke: young trails drawn at least as wide as a grid
Subject: [PATCH 30/34] HD smoke: young trails drawn at least as wide as a grid
cell (density scaled to keep the mass), gentler bulges, so a trail is a
smooth ribbon and not a chain of puffs
@@ -1,7 +1,7 @@
From 35ffbaa26dd91855c8b93446646ba8c58448d3d0 Mon Sep 17 00:00:00 2001
From: chexit <chexit@duck.com>
Date: Fri, 30 Oct 2026 03:59:41 +0300
Subject: [PATCH 31/33] Mods: render.set-main-view (API level 15) renders the
Subject: [PATCH 31/34] Mods: render.set-main-view (API level 15) renders the
screen's world from a mod camera with the full pipeline, so replays get HD
and the post effects; small mod views get the post pass with their own camera
@@ -1,7 +1,7 @@
From 27e24527550942695164dd3a769a42a659e797ca Mon Sep 17 00:00:00 2001
From: chexit <chexit@duck.com>
Date: Fri, 30 Oct 2026 09:28:05 +0300
Subject: [PATCH 32/33] Spot lights for mods (render.set-spot-lights, API level
Subject: [PATCH 32/34] Spot lights for mods (render.set-spot-lights, API level
16): surfaces lit in the cone, a volumetric beam stopped by depth (#60); film
capture (render.capture-*, set-film-quality, API level 17): fixed-step clock,
frames piped to ffmpeg or PNGs, offline audio, no chat in the frames (#58);
@@ -1,7 +1,7 @@
From 615f5c3fa7c19a9895f8972a88333c6f250ad78a Mon Sep 17 00:00:00 2001
From: chexit <chexit@duck.com>
Date: Fri, 30 Oct 2026 14:30:39 +0300
Subject: [PATCH 33/33] HD clouds and fog polish: cloud panorama, cirrus,
Subject: [PATCH 33/34] HD clouds and fog polish: cloud panorama, cirrus,
terrain-aware fog, far smoke cascade; replay world log and film clock;
material overlays by sprite name
File diff suppressed because it is too large Load Diff
+351 -15
View File
@@ -8,6 +8,7 @@
Запуск: python3 tools/gen_models.py
"""
import json
import math
import os
import sys
import random
@@ -1301,20 +1302,355 @@ ITEMS = [
]
def item_icon(color, seed):
rnd = random.Random(seed)
im = Image.new("RGBA", (16, 16), (0, 0, 0, 0))
for y in range(2, 14):
for x in range(4, 12):
im.putpixel((x, y), tuple(clamp(c + rnd.randint(-10, 10)) for c in color) + (255,))
for x in range(5, 11):
im.putpixel((x, 3), (230, 230, 230, 255))
im.putpixel((7, 6), (255, 60, 60, 255))
im.putpixel((8, 6), (255, 60, 60, 255))
for y in range(13, 16):
im.putpixel((7, y), (40, 40, 40, 255))
im.putpixel((8, y), (40, 40, 40, 255))
return im
# Иконки 16×16 без сглаживания. Каждый предмет рисуется своей функцией: категория задаёт основу
# (машина ПВО, пуск с пламенем, РЛС, склад, прожектор, целеуказатель, стрелки, сворачивание),
# внутри категории — мини-силуэт типа. Цвет предмета — только заливка, форма различает предметы.
class _Icon:
def __init__(self, color, seed):
self.rnd = random.Random(seed)
self.im = Image.new("RGBA", (16, 16), (0, 0, 0, 0))
self.pal = {
"b": tuple(color),
"d": tuple(clamp(v * 0.6) for v in color),
"l": tuple(clamp(v + 45) for v in color),
"k": (30, 30, 34), "r": (255, 60, 60), "o": (255, 150, 40),
"y": (255, 232, 120), "w": (236, 236, 236),
}
def px(self, x, y, key):
if 0 <= x < 16 and 0 <= y < 16:
c = self.pal[key]
if key in ("b", "d", "l"):
c = tuple(clamp(v + self.rnd.randint(-6, 6)) for v in c)
self.im.putpixel((x, y), c + (255,))
def rect(self, x0, y0, x1, y1, key):
for y in range(y0, y1 + 1):
for x in range(x0, x1 + 1):
self.px(x, y, key)
def line(self, x0, y0, x1, y1, key):
dx, dy = abs(x1 - x0), -abs(y1 - y0)
sx, sy = (1 if x0 < x1 else -1), (1 if y0 < y1 else -1)
err = dx + dy
while True:
self.px(x0, y0, key)
if x0 == x1 and y0 == y1:
break
e2 = 2 * err
if e2 >= dy:
err += dy
x0 += sx
if e2 <= dx:
err += dx
y0 += sy
def disc(self, cx, cy, r, key):
for y in range(cy - r - 1, cy + r + 2):
for x in range(cx - r - 1, cx + r + 2):
if (x - cx) ** 2 + (y - cy) ** 2 <= r * r + 0.5 * r:
self.px(x, y, key)
def ring(self, cx, cy, lo, hi, key):
for y in range(16):
for x in range(16):
if lo <= (x - cx) ** 2 + (y - cy) ** 2 <= hi:
self.px(x, y, key)
def poly(self, pts, key):
# Выпуклый многоугольник: заливка по строкам между крайними пересечениями рёбер.
n = len(pts)
for y in range(min(p[1] for p in pts), max(p[1] for p in pts) + 1):
xs = []
for i in range(n):
(x1, y1), (x2, y2) = pts[i], pts[(i + 1) % n]
if y1 == y2:
if y1 == y:
xs += [x1, x2]
elif min(y1, y2) <= y <= max(y1, y2):
xs.append(x1 + (y - y1) * (x2 - x1) / (y2 - y1))
if xs:
for x in range(math.ceil(min(xs) - 1e-9), math.floor(max(xs) + 1e-9) + 1):
self.px(x, y, key)
def _sam_base(c):
c.rect(2, 8, 13, 11, "b")
c.rect(3, 12, 4, 13, "k")
c.rect(11, 12, 12, 13, "k")
# Развёртывание ПВО: машина + пусковая установка.
def _gepard(c): # ствольная турель, два длинных ствола
_sam_base(c)
c.disc(7, 6, 2, "b")
c.line(9, 5, 15, 5, "d")
c.line(9, 7, 15, 7, "d")
def _pantsir(c): # ствольная турель с ракетными контейнерами сверху
_sam_base(c)
c.disc(7, 7, 2, "b")
c.rect(4, 3, 5, 5, "l")
c.rect(9, 3, 10, 5, "l")
c.line(9, 6, 11, 6, "d")
def _s400(c): # три вертикальных контейнера
_sam_base(c)
for x in (3, 6, 9):
c.rect(x, 2, x + 1, 7, "b")
c.rect(x, 2, x + 1, 2, "l")
def _s500(c): # четыре вертикальных контейнера
_sam_base(c)
for x in (2, 5, 8, 11):
c.rect(x, 2, x + 1, 7, "b")
c.rect(x, 2, x + 1, 2, "l")
def _patriot(c): # наклонный пусковой короб
_sam_base(c)
c.poly([(3, 8), (11, 3), (13, 5), (5, 10)], "b")
c.line(7, 7, 9, 5, "d")
def _buk(c): # наклонные направляющие с ракетой
_sam_base(c)
c.line(3, 8, 10, 2, "d")
c.line(5, 9, 12, 3, "d")
c.disc(12, 2, 1, "w")
def _irist(c): # два наклонных контейнера
_sam_base(c)
c.poly([(3, 8), (7, 3), (9, 4), (5, 9)], "b")
c.poly([(7, 9), (11, 3), (13, 4), (9, 10)], "b")
def _nasams(c): # два горизонтальных контейнера
_sam_base(c)
c.rect(3, 2, 12, 3, "b")
c.rect(3, 5, 12, 6, "b")
c.line(3, 4, 12, 4, "d")
def _tor(c): # сетка коротких вертикальных ячеек
_sam_base(c)
for x in (3, 6, 9):
c.rect(x, 2, x + 1, 3, "b")
c.rect(x, 5, x + 1, 6, "b")
def _p1sun(c): # короб с мачтой
_sam_base(c)
c.rect(3, 5, 12, 7, "b")
c.line(7, 1, 7, 4, "d")
c.px(7, 1, "r")
# Радиолокация и РЭБ.
def _radar(c): # параболическая антенна на стойке
c.disc(8, 5, 3, "l")
c.line(8, 8, 8, 12, "d")
c.rect(5, 13, 11, 14, "d")
def _ew(c): # штырь-антенна с сигнальными дугами
c.line(8, 6, 8, 14, "d")
c.disc(8, 4, 1, "b")
c.line(5, 2, 4, 4, "l")
c.line(4, 4, 4, 6, "l")
c.line(4, 6, 5, 8, "l")
c.line(11, 2, 12, 4, "l")
c.line(12, 4, 12, 6, "l")
c.line(12, 6, 11, 8, "l")
# Снабжение.
def _depot(c): # штабель ящиков на поддоне
c.rect(3, 8, 12, 13, "b")
c.line(3, 10, 12, 10, "d")
c.line(3, 12, 12, 12, "d")
c.rect(2, 14, 13, 14, "d")
c.rect(4, 4, 9, 7, "l")
c.line(4, 6, 9, 6, "d")
def _tzm(c): # грузовик с кабиной и кузовом
c.rect(2, 7, 5, 11, "b")
c.rect(3, 8, 4, 9, "w")
c.rect(6, 4, 14, 11, "l")
c.rect(3, 12, 4, 13, "k")
c.rect(10, 12, 11, 13, "k")
c.rect(13, 12, 14, 13, "k")
# Прожектор.
def _searchlight(c):
c.rect(3, 4, 10, 8, "b")
c.poly([(10, 4), (15, 1), (15, 11), (10, 8)], "y")
c.line(6, 9, 6, 13, "d")
c.rect(3, 14, 9, 14, "d")
# Целеуказатель: кольцо с засечками.
def _designator(c):
c.ring(8, 8, 16, 26, "r")
c.rect(7, 1, 8, 2, "r")
c.rect(7, 13, 8, 14, "r")
c.rect(1, 7, 2, 8, "r")
c.rect(13, 7, 14, 8, "r")
c.rect(7, 7, 8, 8, "r")
# Пуски: огонь сзади, силуэт типа спереди.
def _launch_base(c):
c.rect(0, 7, 1, 8, "o")
c.px(0, 7, "y")
def _shahed(c): # треугольное крыло
_launch_base(c)
c.poly([(5, 2), (5, 13), (13, 7)], "b")
def _geran3(c): # реактивный самолёт со стреловидным крылом
_launch_base(c)
c.rect(3, 7, 13, 8, "b")
c.poly([(6, 7), (9, 2), (11, 2), (9, 7)], "d")
c.poly([(6, 8), (9, 13), (11, 13), (9, 8)], "d")
c.poly([(3, 7), (4, 3), (5, 3), (5, 7)], "d")
def _lancet(c): # малый дрон с прямым крылом
_launch_base(c)
c.rect(3, 7, 12, 8, "b")
c.rect(7, 2, 8, 13, "d")
c.rect(3, 6, 4, 9, "d")
def _kh101(c): # крылатая ракета: стреловидные крылья и хвост
_launch_base(c)
c.rect(3, 7, 12, 8, "b")
c.poly([(12, 6), (15, 7), (15, 8), (12, 9)], "b")
c.poly([(6, 7), (9, 3), (10, 3), (8, 7)], "d")
c.poly([(6, 8), (9, 12), (10, 12), (8, 8)], "d")
c.rect(2, 5, 3, 10, "d")
def _kalibr(c): # крылатая ракета: тонкий корпус и четыре хвостовых киля
_launch_base(c)
c.rect(2, 7, 13, 8, "b")
c.poly([(13, 6), (15, 7), (15, 8), (13, 9)], "b")
c.rect(2, 4, 3, 5, "d")
c.rect(2, 10, 3, 11, "d")
def _kh22(c): # толстый корпус с большими дельта-крыльями
_launch_base(c)
c.rect(3, 6, 11, 9, "b")
c.poly([(11, 6), (15, 7), (15, 8), (11, 9)], "b")
c.poly([(4, 6), (8, 2), (9, 2), (7, 6)], "d")
c.poly([(4, 9), (8, 13), (9, 13), (7, 9)], "d")
def _zircon(c): # гиперзвук: корпус с одним передним стрейком
_launch_base(c)
c.rect(2, 7, 12, 8, "b")
c.poly([(12, 7), (15, 7), (12, 8)], "b")
c.poly([(8, 7), (12, 3), (13, 3), (11, 7)], "d")
def _iskander(c): # баллистическая: длинный корпус, конус, сопло
_launch_base(c)
c.rect(3, 7, 11, 8, "b")
c.poly([(11, 6), (15, 7), (15, 8), (11, 9)], "l")
c.rect(2, 6, 2, 9, "d")
def _oreshnik(c): # баллистическая с тремя головными частями
_launch_base(c)
c.rect(2, 6, 10, 9, "b")
c.poly([(10, 5), (13, 6), (10, 7)], "l")
c.poly([(10, 8), (13, 9), (10, 10)], "l")
c.poly([(10, 6), (15, 7), (10, 8)], "b")
def _kinzhal(c): # аэробаллистическая: корпус с треугольными килями
_launch_base(c)
c.rect(3, 7, 11, 8, "b")
c.poly([(11, 6), (15, 7), (11, 9)], "b")
c.poly([(4, 7), (7, 3), (8, 3), (6, 7)], "d")
c.poly([(4, 8), (7, 12), (8, 12), (6, 8)], "d")
def _mover(c): # четыре стрелки перемещения
c.poly([(8, 0), (4, 5), (12, 5)], "b")
c.rect(7, 4, 8, 7, "b")
c.poly([(8, 15), (4, 10), (12, 10)], "b")
c.rect(7, 8, 8, 11, "b")
c.poly([(0, 8), (5, 4), (5, 12)], "b")
c.rect(4, 7, 7, 8, "b")
c.poly([(15, 8), (10, 4), (10, 12)], "b")
c.rect(8, 7, 11, 8, "b")
def _remover(c): # стрелка вниз над лотком: свёртывание
c.poly([(8, 9), (3, 4), (13, 4)], "b")
c.rect(7, 1, 8, 4, "b")
c.rect(2, 11, 13, 13, "b")
c.line(2, 11, 13, 11, "l")
def _flare(c): # звезда осветительной ракеты на стержне
c.disc(8, 7, 1, "y")
c.line(8, 2, 8, 4, "y")
c.line(8, 10, 8, 12, "y")
c.line(3, 7, 5, 7, "y")
c.line(11, 7, 13, 7, "y")
c.line(4, 4, 5, 5, "w")
c.line(11, 4, 10, 5, "w")
c.line(4, 10, 5, 9, "w")
c.line(11, 10, 10, 9, "w")
c.rect(7, 12, 8, 15, "k")
ICON_DRAW = {
"designator": _designator,
"launch_shahed": _shahed, "launch_geran3": _geran3, "launch_lancet": _lancet,
"launch_kh101": _kh101, "launch_kalibr": _kalibr, "launch_kh22": _kh22,
"launch_zircon": _zircon, "launch_iskander": _iskander, "launch_oreshnik": _oreshnik,
"launch_kinzhal": _kinzhal,
"deploy_patriot": _patriot, "deploy_gepard": _gepard, "deploy_pantsir": _pantsir,
"deploy_s400": _s400, "deploy_s500": _s500, "deploy_irist": _irist,
"deploy_nasams": _nasams, "deploy_buk": _buk, "deploy_tor": _tor, "deploy_p1sun": _p1sun,
"deploy_radar": _radar, "deploy_ew": _ew,
"deploy_depot": _depot, "deploy_tzm": _tzm,
"deploy_light": _searchlight,
"mover": _mover, "remover": _remover, "flare_gun": _flare,
}
def item_icon(name, color, seed):
c = _Icon(color, seed)
ICON_DRAW[name](c)
# Контур по краю силуэта: тёмные предметы — светлым, светлые — тёмным, чтобы читались на обоих фонах.
# Альфа-маска не меняется: контур перекрашивает только уже нарисованные пиксели.
lum = 0.3 * color[0] + 0.59 * color[1] + 0.11 * color[2]
edge = (160, 160, 160) if lum < 100 else (70, 70, 70) if lum > 190 else None
if edge:
src = c.im.copy()
def opaque(x, y):
return 0 <= x < 16 and 0 <= y < 16 and src.getpixel((x, y))[3] > 0
for y in range(16):
for x in range(16):
if opaque(x, y) and not all(opaque(x + dx, y + dy) for dx, dy in ((1, 0), (-1, 0), (0, 1), (0, -1))):
c.im.putpixel((x, y), edge + (255,))
return c.im
def write_json(path, obj):
@@ -1350,7 +1686,7 @@ def main():
im = GT.burn(im, zlib.crc32(name.encode()), "glass" if base.startswith("glass") else "paint")
im.save(os.path.join(a, "textures", "block", name + ".png"))
for i, (name, title, color) in enumerate(ITEMS):
item_icon(color, i).save(os.path.join(a, "textures", "item", name + ".png"))
item_icon(name, color, zlib.crc32(name.encode())).save(os.path.join(a, "textures", "item", name + ".png"))
write_json(os.path.join(a, "models", "item", name + ".json"),
{"parent": "minecraft:item/generated", "textures": {"layer0": f"{NS}:item/{name}"}})
write_json(os.path.join(a, "items", name + ".json"),