diff options
Diffstat (limited to 'docs/tomes')
| -rw-r--r-- | docs/tomes/05-render.md | 70 |
1 files changed, 51 insertions, 19 deletions
diff --git a/docs/tomes/05-render.md b/docs/tomes/05-render.md index 01038b7..b04af31 100644 --- a/docs/tomes/05-render.md +++ b/docs/tomes/05-render.md @@ -87,7 +87,9 @@ drivers и video modes, проверяет поддержку 3D, перевод современная реализация заменяет наблюдаемую fixed-function семантику над этой границей, а не должна эмулировать COM-объекты DirectX. Равный SHA-256 Ngi32 в Частях 1 и 2 зафиксирован в [таблице оригинальных модулей](../reference/original-binaries.md); -это поддерживает единый контракт Vulkan backend. +это поддерживает единый контракт Vulkan backend. RVA относятся к конкретной +сборке DLL: перед переносом адреса на другую установку сверяйте размер и +SHA-256 соответствующего модуля в этой таблице. ```text enumerate adapters and video modes @@ -173,10 +175,11 @@ struct Node38 { }; ``` -`slot_index` образует матрицу `3 LOD x 5 groups`. Выбор выполняется как -`slot_index[lod * 5 + group]`; `0xFFFF` означает отсутствие geometry для этой -комбинации. Поле `parent_or_link` участвует в иерархии или связи узлов, но -название остаётся описательным. +`slot_index` хранит 3 состояния по 5 LOD: `slot_index[state * 5 + lod]`; +`0xFFFF` означает отсутствие геометрии для комбинации. Публичные Rust-обёртки +сохраняют исторические имена `Lod` и `Group`: аргумент `Lod` задаёт нативное +состояние (0..2), а `Group` — нативный уровень LOD (0..4). Поле `parent_or_link` +участвует в иерархии или связи узлов, но название остаётся описательным. Type 2 начинается с header `0x8C`, затем содержит slots по 68 байт: @@ -269,7 +272,7 @@ static_assert(sizeof(Batch20) == 20); ```c for (Node& node : model.nodes) { Matrix node_world = parent_world * local_transform(node); - uint16_t sid = node.slot_index[lod * 5 + group]; + uint16_t sid = node.slot_index[native_state * 5 + native_lod]; if (sid == 0xFFFF) continue; Slot& slot = model.slots[sid]; @@ -306,17 +309,17 @@ render queues и сортировка, но связи данных остают struct AnimKey24 { float position[3]; float time; + int16_t qw; int16_t qx; int16_t qy; int16_t qz; - int16_t qw; }; ``` -Quaternion components декодируются как signed value / `32767.0`. На диске -порядок полей XYZ-W, но runtime math использует логическое `[w, x, y, z]`. -Безусловная современная нормализация после чтения не добавляется без parity -проверки: она может изменить крайние кадры. +На диске quaternion записан в порядке WXYZ; каждый signed component +декодируется делением на `32767.0`. Декодер переставляет поля в portable +`Pose.rotation = [x, y, z, w]` и оставляет их ненормализованными. Нормализация +выполняется при подготовке pose к sampling. Type 19 является массивом `uint16_t`; его `attr2` задаёт общее число кадров timeline. Для конкретного узла `anim_map_start` указывает на блок длиной @@ -622,14 +625,18 @@ Lightmap не является обычной diffuse texture. WEAR содерж отдельным slot или texture stage. Замена lightmap предварительным умножением в diffuse texture ломает LOD, atlas coordinates и динамическую модуляцию. -Тени проходят отдельным render pass. Terrain содержит пути для теней зданий и -роботов, ограничения максимального числа, detail level и smoothing. Реализованы -native visibility по шести Vulkan clip-плоскостям с радиусом sphere +100, -порядок кандидатов и лимит 20 до построения страниц, projected-size LOD, -directional/point light contribution, native page layout, raster, smoothing и -receiver projection с edge clipping. Unknown settings из `shade.cfg` читаются и -сохраняются по именам, а не заменяются произвольными modern defaults. Для native ray query -surface descriptor в `+0x10` требует наличия всех переданных bits, а descriptor +Vulkan preview строит projected shadows для выбранных зданий и роботов, +отбрасывает spheres вне шести clip-плоскостей с радиусом `sphere + 100` и +сохраняет порядок видимых кандидатов; frame builder обрабатывает не более 20 +casters. Текущая реализация выделяет страницы в atlas `256 x 256` с 28 page +slots и использует одну smoothing pass. Вызов preview передаёт `fade = 1.0` и +LOD defaults: minimum LOD `1` и detail multiplier `1.0` отдельно для зданий и +роботов. Rust-путь не загружает `shade.cfg`: эти значения задаются кодом, а +параметры файла пока не влияют на preview. Проекция учитывает вклад +directional и point lights. + +Receiver projection обрезает projected quad по рёбрам треугольника. Native ray +query descriptor в `+0x10` требует наличия всех переданных bits, а descriptor в `+0x14` исключает поверхности с любым переданным bit. Общий shadow query использует full exclusion mask `0x2000`; actor four-ray path получает compact mask `0x8008`, который landscape boundary разворачивает в full mask @@ -923,6 +930,31 @@ sun-ray queries поэтому используют исходные коордÐ Эти два указателя нельзя подменять друг другом. Формулы камеры и размещения реализованы и проверяются в `fparkan-render`. +## LOD ландшафта + +У `Land.msh` список slot-ссылок terrain хранится в 38-байтовых записях +Node38, а диапазоны граней — в 68-байтовых Slot68. В текущем runtime первые +две ссылки Node38 выбирают соответственно LOD0 и LOD1; каждая запись слота +задаёт начало и число граней в исходном массиве `TerrainFace28`. Все грани +проверяются на единственное назначение, а выходящий за массив, повторный или +неподдерживаемый диапазон считается ошибкой загрузки. + +Первый рендер карты, terrain-запросы высоты и пересечения, receiver-ы теней и +обрезка контуром зданий используют только LOD0. Отбор сохраняет порядок +исходных граней, а контурный проход отдельно переводит индекс спроецированной +грани обратно в исходный. LOD1 пока не подставляется по расстоянию: такой +переход не реализован. + +```rust +let assignments = mesh.face_lod_assignments()?; +for (face, assignment) in mesh.faces.iter().zip(assignments.iter()) { + if assignment.lod != TerrainLod::Lod0 { + continue; + } + // Build terrain query geometry from this source face. +} +``` + ## Материалы ландшафта Рядом с `Land.msh` лежат `Land1.wea` и `Land2.wea`. Старший байт |
