Допустим, вы хотите перенести модельку из одной игры в другую.
Классический путь — извлечь, перегнать в промежуточный формат, адаптировать под целевой движок и собрать заново. Звучит рационально, практично и таких решений немало:
OpenAssetTools / ZoneTool автоматизируют процесс конвертации для Call of Duty
UE Viewer экспортирует данные Unreal в GLTF, PSK, DDS и др.
Мы сегодня рассмотрим альтернативный путь. Как вам идея переписать рантайм целевой игры с нуля и добавить нативную поддержку чужих ассетов? Моя попытка сделать что‑то подобное привела к созданию экспериментального движка IW4L, основой для которого является IW4 (Call of Duty Modern Warfare 2 2009).


Вместо такого пути:
ассет игры A -> конвертация отдельным софтом -> формат игры B -> рантайм игры B
В IW4L я попытался убрать среднюю часть:
ассеты игр A В С -> IW4L
Рантайм должен сам найти данные, понять откуда пришли, как их разобрать и как правильно исполнить. Modern Warfare 2, Black Ops 1 и Modern Warfare 3 используют разные поколения одного семейства движков, а их fastfile‑архивы отличаются как разрядностью так и внутренними структурами, это если говорить о файлах. Но прочитать файл, увы, оказалось самой простой частью((
Шейдеры
Представьте, что сцена состоит из карты MW2, оружия из BlackOps и ещё одной модели на спине из MW3. Геометрию всех трёх можно сравнительно легко довести до общего представления: вершины и текстуры... терпимо! Но как теперь всё это отобразить? Отображением вершин, текстур, освещения, материалов, эффектов занимаются небольшие програмы, которые выполняются на GPU — шейдеры.
В оригинальных играх шейдеры хранятся в виде байт‑кода Shader Model 3 для Direct3D 9. У нас Direct3D нет: рантайм написан на модном молодёжном Rust / Bevy, графическое API у нас wgpu. Нужен слой SM3 → WGSL.
К счастью, сама иде не новая. DXVK решает гораздо более общую задачу: принимает Direct3D и исполняет его поверх Vulkan. В том числе внутри него есть полноценный путь трансляции нужного нам D3D9 в SPIR‑V. Так что устройство SM3, декодирование инструкций и огромное количество неприятных кейсов уже исследованы до нас.
Но вот только MW2, Black Ops и MW3 пусть и объединяет формат Shader Model 3, содержимое этих инструкций заметно отличаются. Причём иногда довольно радикально отличаются программы, имеющие одинаковые имена.
Просто сделать глобальную таблицу вида
shader_name -> translated_shader
не получится!
Нам приходится сохранять ещё одно измерение:
(game, shader) -> translated_shader
Рантайм должен помнить происхождение ресурса вплоть до самого этапа отрисовки. Если перед нами модель из Black Ops, недостаточно знать название её материала. Нужно:
знать, что материал относится к T5;
выбрать соответствующую T5-технику отрисовки;
загрузить нужные для T5 вершинные и пиксельные шейдеры;
правильно подготовить ожидаемые ими константы;
передать всё это в общий конвейер отрисовки.
Шейдер ожидает: матрицы, положение камеры, параметры света, тумана, материала и другие значения, которые исходный движок готовил перед отрисовкой. Между MW2, Black Ops и MW3 различается как набор этих данных, так и интерпретация.
Освещение
Вы видите на видео: карта Afghan загружена из MW2, а FAMAS в руках игрока — из Black Ops. Геометрия, текстуры и шейдер оружия загружены правильно. Но само оружие выглядит слишком ярким.
Причина в том, что карта формирует освещение по правилам IW4, а материал оружия ожидает данные по правилам T5. Шейдер успешно выполняется, ничего не падает, но получает не совсем те значения, на которые рассчитывал.
Получается сцена, где одновременно могут существовать:
IW5 карта -> IW4/T5 оружие -> IW5 освещение -> IW4 пайплайн отрисовки одного несчастного кадра
Именно здесь поддержка чужих файлов превращается в задачу совместимости нескольких поколений движка внутри одного кадра. Получится ли решить все такие пограничные кейсы взаимодействия карт/оружия/и так далее? Понятия не имею.
Для справки приведу скриншоты того, какие результаты показывал этот движок 11 августа (чуть меньше 4 недель назад):


Мне будет очень интересно закинуть статью ещё через месяц и показать прогресс, если зайдёт (:
Ремарки касательно использования AI: Проект написан десятками различных ЛЛМ и состоит из порядка ~370тыс строк на сегодняшний день. Статья написана человеком.

