2026-02-19 04:46:23 +04:00
|
|
|
|
# Material (`MAT0`)
|
|
|
|
|
|
|
|
|
|
|
|
`MAT0` описывает материал и его фазовую анимацию.
|
|
|
|
|
|
|
|
|
|
|
|
Связанные страницы:
|
|
|
|
|
|
|
|
|
|
|
|
- [Wear table (`WEAR`)](wear.md)
|
|
|
|
|
|
- [Texture (`Texm`)](texture.md)
|
|
|
|
|
|
- [Render pipeline](render.md)
|
|
|
|
|
|
|
|
|
|
|
|
## 1. Контейнер
|
|
|
|
|
|
|
|
|
|
|
|
- Тип ресурса: `0x3054414D` (`MAT0`).
|
|
|
|
|
|
- Обычно хранится в `Material.lib`.
|
|
|
|
|
|
- `attr1` используется как битовое поле runtime-флагов материала.
|
|
|
|
|
|
- `attr2` задаёт версию заголовка payload.
|
|
|
|
|
|
|
|
|
|
|
|
## 2. Бинарный layout
|
|
|
|
|
|
|
|
|
|
|
|
```c
|
|
|
|
|
|
struct Mat0Payload {
|
|
|
|
|
|
uint16_t phaseCount;
|
|
|
|
|
|
uint16_t animBlockCount; // должно быть < 20
|
|
|
|
|
|
|
|
|
|
|
|
// если attr2 >= 2
|
|
|
|
|
|
uint8_t metaA8;
|
|
|
|
|
|
uint8_t metaB8;
|
|
|
|
|
|
// если attr2 >= 3
|
|
|
|
|
|
uint32_t metaC32;
|
|
|
|
|
|
// если attr2 >= 4
|
|
|
|
|
|
uint32_t metaD32;
|
|
|
|
|
|
|
|
|
|
|
|
PhaseRecord34 phases[phaseCount];
|
|
|
|
|
|
AnimBlockRaw anim[animBlockCount];
|
|
|
|
|
|
};
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Если `attr2 < 2`, используются runtime-значения по умолчанию:
|
|
|
|
|
|
|
|
|
|
|
|
- `metaA = 255`
|
|
|
|
|
|
- `metaB = 255`
|
|
|
|
|
|
- `metaC = 1.0f`
|
|
|
|
|
|
- `metaD = 0`
|
|
|
|
|
|
|
|
|
|
|
|
## 3. Фазы материала
|
|
|
|
|
|
|
|
|
|
|
|
```c
|
|
|
|
|
|
struct PhaseRecord34 {
|
|
|
|
|
|
uint8_t params[18];
|
|
|
|
|
|
char textureName[16];
|
|
|
|
|
|
};
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
В рантайме запись разворачивается в структуру ~76 байт:
|
|
|
|
|
|
|
|
|
|
|
|
- набор коэффициентов цвета/освещения/прозрачности;
|
|
|
|
|
|
- индекс слота текстуры;
|
|
|
|
|
|
- дополнительные целочисленные поля.
|
|
|
|
|
|
|
|
|
|
|
|
`textureName`:
|
|
|
|
|
|
|
|
|
|
|
|
- пустая строка -> фаза без текстуры (`texSlot = -1`);
|
|
|
|
|
|
- непустая строка -> загрузка текстуры по имени.
|
|
|
|
|
|
|
|
|
|
|
|
## 4. Анимационные блоки
|
|
|
|
|
|
|
|
|
|
|
|
```c
|
|
|
|
|
|
struct AnimBlockRaw {
|
|
|
|
|
|
uint32_t headerRaw; // mode = low 3 bits, interpMask = остальные
|
|
|
|
|
|
uint16_t keyCount;
|
|
|
|
|
|
KeyRaw keys[keyCount];
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
struct KeyRaw {
|
|
|
|
|
|
uint16_t k0;
|
|
|
|
|
|
uint16_t k1;
|
|
|
|
|
|
uint16_t k2; // opaque, сохранять 1:1
|
|
|
|
|
|
};
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
`k2` нельзя удалять или нормализовать: это часть бинарного контракта.
|
|
|
|
|
|
|
|
|
|
|
|
## 5. Выбор текущей фазы
|
|
|
|
|
|
|
|
|
|
|
|
Материал выбирает фазу по времени и по режиму анимации блока:
|
|
|
|
|
|
|
|
|
|
|
|
- loop;
|
|
|
|
|
|
- ping-pong;
|
|
|
|
|
|
- one-shot с clamp;
|
|
|
|
|
|
- random-offset.
|
|
|
|
|
|
|
|
|
|
|
|
При смешивании интерполируется только часть полей, остальные копируются из активной фазы.
|
|
|
|
|
|
Для 1:1 совместимости важно сохранить эту выборочную интерполяцию.
|
|
|
|
|
|
|
|
|
|
|
|
## 6. Загрузка и fallback
|
|
|
|
|
|
|
|
|
|
|
|
При запросе материала по имени:
|
|
|
|
|
|
|
|
|
|
|
|
1. Точный поиск по имени.
|
|
|
|
|
|
2. Если не найдено — fallback на `DEFAULT`.
|
|
|
|
|
|
3. Если `DEFAULT` отсутствует — используется запись с индексом `0`.
|
|
|
|
|
|
|
|
|
|
|
|
## 7. Атрибуты и флаги
|
|
|
|
|
|
|
|
|
|
|
|
Практически важные биты `attr1`:
|
|
|
|
|
|
|
|
|
|
|
|
- бит загрузки текстурной фазы с расширенными флагами;
|
|
|
|
|
|
- флаги аппаратного профиля;
|
|
|
|
|
|
- 4-битный режим (`nibbleMode`);
|
|
|
|
|
|
- дополнительный флаг material-поведения.
|
|
|
|
|
|
|
|
|
|
|
|
Неизвестные биты должны сохраняться без изменений.
|
|
|
|
|
|
|
|
|
|
|
|
## 8. Ограничения
|
|
|
|
|
|
|
|
|
|
|
|
- `animBlockCount < 20`
|
|
|
|
|
|
- `phaseCount` и фактический размер секции фаз должны совпадать
|
|
|
|
|
|
- `textureName` должен быть NUL-terminated и укладываться в 16 байт
|
|
|
|
|
|
|
|
|
|
|
|
## 9. Правила writer/editor
|
|
|
|
|
|
|
|
|
|
|
|
1. Сохранять `attr1/attr2/attr3`.
|
|
|
|
|
|
2. Не менять `metaA/B/C/D` без явного запроса.
|
|
|
|
|
|
3. Сохранять opaque-поля анимации (включая `k2`) 1:1.
|
|
|
|
|
|
4. Проверять выход за границы payload при парсинге.
|
|
|
|
|
|
|
|
|
|
|
|
## 10. Статус валидации
|
|
|
|
|
|
|
|
|
|
|
|
- Инварианты MAT0 зафиксированы в текущем toolchain проекта (`docs/specs` + `tools`).
|
2026-02-19 11:07:04 +04:00
|
|
|
|
- Структурная валидация MAT0 включена в корпусный прогон `tools/msh_doc_validator.py` на полном retail-наборе.
|
|
|
|
|
|
|
|
|
|
|
|
## 11. Статус покрытия и что осталось до 100%
|
|
|
|
|
|
|
|
|
|
|
|
Закрыто:
|
|
|
|
|
|
|
|
|
|
|
|
1. Бинарный layout `MAT0` и правила чтения фаз/анимационных блоков.
|
|
|
|
|
|
2. Fallback-цепочка материала.
|
|
|
|
|
|
3. Контракт сохранения opaque-полей для lossless editor path.
|
|
|
|
|
|
|
|
|
|
|
|
Осталось:
|
|
|
|
|
|
|
|
|
|
|
|
1. Полная семантика всех битов `attr1` и `metaA/B/C/D` для авторинга новых материалов.
|
|
|
|
|
|
2. Полный writer-профиль «канонический MAT0» для генерации ассетов без copy-through.
|
|
|
|
|
|
3. Набор визуальных parity-тестов по material phase animation на реальных моделях.
|