# 3D implementation notes Контрольная страница с практическими правилами реализации 3D-пайплайна и с перечнем незакрытых зон. Документ intentionally high-level: без ссылок на внутренние функции/адреса. Связанные страницы: - [MSH core](msh-core.md) - [MSH animation](msh-animation.md) - [Material (`MAT0`)](material.md) - [Texture (`Texm`)](texture.md) - [FXID](fxid.md) - [Render pipeline](render.md) ## 1. Базовые двоичные правила 1. Все форматы в этой подсистеме little-endian. 2. Внутри NRes данные ресурсов выравниваются по 8 байт. 3. Внутри payload таблиц padding между записями обычно отсутствует: записи идут подряд по stride. ## 2. Быстрая карта stride'ов | Ресурс | Запись | Stride | |---|---|---:| | Res1 | Node | 38 | | Res2 | Slot | 68 (после header `0x8C`) | | Res3 | Position | 12 | | Res4 | Normal | 4 | | Res5 | UV0 | 4 | | Res6 | Index | 2 | | Res7 | Tri descriptor | 16 | | Res8 | Animation key | 24 | | Res13 | Batch | 20 | | Res19 | Animation map | 2 | ## 3. Декодирование ключевых потоков ## 3.1. Позиции (Res3) `float3`, stride `12`. ## 3.2. Нормали (Res4) `int8[4]`, используются первые 3 компоненты: ```text n = clamp(s8 / 127.0, -1..1) ``` ## 3.3. UV (Res5) `int16[2]`: ```text u = s16 / 1024.0 v = s16 / 1024.0 ``` ## 3.4. Animation key (Res8) `pos(float3) + time(float) + quat(int16x4)`: ```text q = s16 / 32767.0 ``` ## 4. Практический reader-контракт Для runtime-совместимого чтения модели: 1. Найти нужные ресурсы по `type_id` в NRes. 2. Проверить `size/stride`-инварианты. 3. Проверить диапазоны ссылок: - slot -> batch/triangles; - batch -> indices; - indices -> vertices; - anim_map -> anim_keys. 4. Неизвестные поля и неизвестные ресурсы сохранять через copy-through. ## 5. Практический writer-контракт 1. Пересчитывать только явно вычислимые поля. 2. Не нормализовать opaque-данные без уверенной спецификации. 3. При roundtrip неизмененных данных требовать byte-identical результат. 4. Для новых ассетов фиксировать отдельную политику «генерация vs preserve». ## 6. Runtime-связка материалов и текстур Канонический путь резолва: 1. Модель -> wear-таблица (`*.wea`). 2. Wear-слот -> material name. 3. Material -> текущая фаза -> `textureName`. 4. `Texm` ищется в `Textures.lib` (или lightmap-библиотеке для lightmap-ветки). Fallback: - материал: `DEFAULT`, затем индекс `0`; - текстура/lightmap: fallback-слот движка. ## 7. Что уже закрыто для 1:1 1. Бинарный контракт базовых MSH таблиц. 2. Контракт animation sampling (`Res8 + Res19`). 3. Контракт MAT0/WEAR/Texm на уровне чтения и применения в кадре. 4. Формат FXID-контейнера, командный поток и fixed command sizes. 5. Валидация на retail-корпусе через `tools/msh_doc_validator.py` (0 ошибок/предупреждений). ## 8. Статус покрытия и что осталось до 100% 1. Полная field-level семантика части служебных полей: - `Batch20` opaque-поля; - хвостовые служебные поля slot-записей; - часть флагов узлов/групп. 2. Полный writer-путь для авторинга новых анимированных ассетов (не только roundtrip существующих). 3. Полная формализация семантики FX payload полей по каждому opcode для генерации новых эффектов, а не только для корректного чтения/исполнения. 4. Полный канонический writer `Texm` для всех редких форматов и edge-case комбинаций служебных флагов. 5. Сквозной «импорт внешнего ассета -> игровой пакет» с формальной спецификацией sidecar-метаданных (материал/эффект/анимация).