- Обновлены спецификации `runtime-pipeline`, `sound`, `terrain-map-loading`, `texture`, `ui` и `wear`. - Добавлены разделы о статусе покрытия и оставшихся задачах для достижения 100% завершенности. - Внесены уточнения по архитектурным ролям, минимальным контрактам и требованиям к toolchain для каждой подсистемы. - Уточнены форматы данных и правила взаимодействия между компонентами системы.
5.0 KiB
5.0 KiB
MSH animation
MSH animation описывает связку Res8 + Res19 и runtime-правила сэмплирования/смешивания поз.
Связанные страницы:
1. Ресурсы анимации
1.1. Res8 (пул ключей)
struct AnimKey24 {
float pos_x;
float pos_y;
float pos_z;
float time;
int16_t qx;
int16_t qy;
int16_t qz;
int16_t qw;
};
Декодирование quaternion-компонент: q = s16 / 32767.0.
1.2. Res19 (карта кадров)
uint16_t map_words[]; // size/2 элементов
Res19.attr2 хранит глобальную длину таймлайна (число кадров).
1.3. Связь с Res1
Для каждого узла:
anim_map_start(hdr2) — начало блока вRes19или0xFFFF.fallback_key(hdr3) — индекс fallback-ключа вRes8.
2. Сэмплирование узла
Вход: время t, текущий узел.
Выход: quat(w,x,y,z) и pos(x,y,z).
2.1. Индекс кадра
Движок использует x87-совместимое округление для выражения t - 0.5.
Для 1:1 повторения нужно сохранить ту же политику плавающей точки.
2.2. Выбор key index
- Если кадр вне диапазона
frame_count->fallback_key. - Если
anim_map_start == 0xFFFF->fallback_key. - Иначе берётся
map_words[anim_map_start + frame]:- если значение
>= fallback_key, тоже используетсяfallback_key; - иначе используется значение из map.
- если значение
2.3. Интерполяция
Если выбран fallback, возвращается ровно этот ключ без интерполяции.
Иначе:
- Берутся соседние ключи
k0иk1. - Если
tточно равенk0.timeилиk1.time, возвращается соответствующий ключ. - Иначе:
alpha = (t - k0.time) / (k1.time - k0.time)pos = lerp(k0.pos, k1.pos, alpha)quat = slerp_like(k0.quat, k1.quat, alpha)
Кватернион в runtime хранится в порядке [w, x, y, z].
3. Смешивание двух сэмплов
При blending между позами A и B:
- Выбираются валидные стороны по
blendи валидности времени. - Если активна одна сторона, берётся она.
- Если активны обе:
- применяется shortest-path flip для
qB; - выполняется quaternion blend;
- позиция смешивается линейно.
- применяется shortest-path flip для
Матрица строится из quaternion, а translation подставляется отдельным шагом.
4. Каноника writer
Рекомендуемые правила:
- Ключи узлов писать подряд в
Res8в порядке узлов. fallback_keyузла указывает на последний ключ его трека.- Для узлов с map выделять блок длины
frame_countвRes19. - Для статических узлов:
anim_map_start = 0xFFFF, один ключ сtime=0. Res8.attr1 = key_count,Res8.attr3 = 4.Res19.attr1 = map_word_count,Res19.attr2 = frame_count,Res19.attr3 = 2.
5. Валидация перед сохранением
Res8.size % 24 == 0Res19.size % 2 == 0- каждый
fallback_key < key_count - для узла с map:
anim_map_start + frame_count <= map_word_count - внутри трека времена ключей строго возрастают
6. Статус валидации
- Форматные проверки включены в
tools/msh_doc_validator.py. - Корпусная валидация анимационных инвариантов включена в прогон
tools/msh_doc_validator.pyна полном retail-наборе.
7. Статус покрытия и что осталось до 100%
Закрыто:
- Контракт
Res8 + Res19и fallback-логика выбора ключа. - Базовая интерполяция поз и blending двух сэмплов.
- Канонические инварианты writer path для существующих ассетов.
Осталось:
- Полная фиксация численного поведения на всех FP-edge-case (включая платформенные различия округления).
- Полный writer-профиль для авторинга новых анимаций без опоры на reference copy-through.
- Набор runtime parity-тестов «frame-by-frame pose equivalence» на длинных анимациях.