Еще одна статья о разборе форматов, для летнего воскресного вечера, небольшая и развлекательная. На этот раз речь пойдёт о 3d-моделях. Принципы хранения данных для любых моделей одинаковы, но форматы файлов весьма разнообразны. Даже в условиях одного и того же движка разработчики норовят всё модифицировать и впихнуть что-нибудь своё, ведь в коммерческих версиях у них есть возможность менять код движка, и они ей обычно пользуются.
Основной объём любого файла с моделью составляют несколько больших таблиц с данными о вершинах, о том, как они соединяются и как на них натягиваются текстуры. Начнём с вершин. Простой список с координатами x,y,z может выглядеть например так:
Так как чаще всего координаты лежат в виде 32-битных плавающих чисел, их легко распознать внутри файла по повторяющимся через 4 байта цифрам в диапазоне 40-45, или для отрицательных чисел C0-C5. Конечно встречаются и другие байты, но эти чаще всего. Так происходит потому, что диапазон координат 3d-модели небольшой с точки зрения порядка, а порядок как раз хранится в старшем байте.
Далее, нужна таблица, где указано, в каком порядке вершины соединяются в треугольники. Чаще всего она выглядит так:
Это 16-битные номера вершин, группами по три. Так как в моделях обычно не более нескольких сотен вершин, числа эти маленькие, и такую таблицу тоже легко видно визуально. В данном примере выделен один из треугольников, состоящий из вершин с номерами 50,51 и 52.
И третья — таблица текстурных координат, чтобы привязать вершины к плоской текстуре, которую нужно на них натянуть.
Координаты x и y в пределах текстуры приводятся к диапазону от 0 до 1, и если текстура имеет размер 2048x2048 или 4096x4096, нет смысла в высокой точности. Поэтому они чаще всего хранятся как плавающие числа с половинной точностью, 16 битные. Старший байт у них получается чуть больше 0x30, изредка доходя до 0x40 или чуть больше. Здесь красным и оранжевым выделены текстурные координаты, зеленым и светло-зеленым — координаты на карте освещения.
После того, как найдены эти таблицы, можно посчитать количество элементов, найти, где это количество хранится и как описывается вся структура. Но кроме этих таблиц в файле обязательно найдутся много мелких непонятных чисел, которые неизвестно к чему относятся и что означают. Вот например, в середине файла с моделью человека имеются три плавающих единицы (выделены зеленым):
Как узнать, что они обозначают? Да просто поменять их и посмотреть, что получится. Запишем вместо них 1,5 и запустим игру
Ну конечно, это масштаб. Интересный эффект получается от того, что анимация записана в других файлах отдельно, и она завязана на координаты в моделях, поэтому возникают такие причудливые уродцы. У мужчины на площади на плечах сидит ребенок. Теперь он оказался у него внутри грудной клетки. Человек перед шлагбаумом, совершающий непонятные движения, на самом деле аплодирует.
Теперь попробуем определить, где здесь ширина, а где высота. Изменим только одно число, первое: уменьшим его в 10 раз.
Таким образом, экспериментируя, можно определить значение оставшихся чисел. Если же при изменении каких-то из них ничего не происходит, просто оставим их в покое. Может быть мы никогда не узнаем, зачем они нужны. А если вдруг однажды они дадут о себе знать — тогда и будем разбираться.
Вот один из примеров, когда разобрать формат файла аналитически бывает легче и быстрее, чем изучать exe-шник, где можно заблудиться в дебрях кода, скармливающего всю эту информацию видеоподсистеме.
Комментарии (12)
saboteur_kiev
19.07.2015 23:16Реверс-инженеринг 3д форматов впервые делал в Elite для ZX-Spectrum. Там 3д модели кораблей были простые, разобраться было несложно. Наделал кучку совершенно других моделей, было весело.
Сейчас реверс-инженеринг с последующим ковырянием модели в hex-едиторе выглядит как-то по-детски. Гораздо проще выдрать модель целиком и отредактировать ее в соответствующем редакторе.
Тем более, что на самом деле гораздо удобнее взять редактор моделей, который подходит для определенного движка, и модели поправить в нем.
Также можно создать в нем простейшие модели каких-либо фигур, и реверсить на них, а не на таких сложных моделях как фигура человека со всеми его формами.AllexIn
19.07.2015 23:23+1Никто не говорит о редактировании модели в HEX редакторе.
Речь о том, чтобы разобрать формат и потом сделать импортер/экспортер, например.Mrrl
20.07.2015 02:34Импортёр — ладно. Но для экспортёра понадобится знать, что прописывать в те самые магические числа, смысла которых понять не удалось. Если новая модель будет хотя бы иногда показывать что-то правдоподобное — то уже повезло. Но скорее всего, при небольшом изменении топологии или числа вершин/треугольников всё сломается так, что не разберёшь.
ID_Daemon Автор
19.07.2015 23:30+3Я потому и написал в самом начале, что разработчики модифицируют движки. Ни один редактор обычно не подходит.
SHVV
20.07.2015 10:00+1Что-то маловато написали.
Думаю, стоит упомянуть ещё несколько таблиц, которые тоже бывают: нормали (возможно со знаком бинормали в третьем компоненте), веса костей для скелетной анимации. Ещё текстурных координат может быть два набора (для стационарной геометрии).
Таблицы могут записываться как отдельно, так и вперемешку (то есть все компоненты вершины описывается одной записью), так как во втором случае производительность несколько выше.
Ещё могут быть лоды, описания габартных контейнеров, сам скелет с иерархией костей и т.д.
AllexIn
Аналогичным образом в свое время разобрал формат карт для Периметра.
Но все гораздо хуже в проектах, которые следят за целостностью файлов или как-то пакуют данные.
Правда последнее время большинство разработчиков этого не делают, потому что аппаратные ресурсы практически безграничные, а шифроваться нет смысла, т.к. модо-творчество — путь к второй жизни игры.
ID_Daemon Автор
Упаковка сейчас очень широко используется. Пример был в прошлой статье: habrahabr.ru/post/261561
AllexIn
Мне кажется это скорее исключение.
Я на своей практике встречал игру в которой данные не просто паковались, а еще и шифровались… Но это тоже скорее исключение. :)
Как правило данные лежат в виде максимально комфортном для быстрой загрузки, что существенно упрощает их обработку.
ID_Daemon Автор
По моему опыту, наоборот. Большинство «больших» игр пакует либо все ресурсы, либо за исключением видео и звука, которые всё равно сильно не сжимаются.
beeruser
>> либо за исключением видео и звука, которые всё равно сильно не сжимаются
Они _уже_ пожаты. Кто-то хранит голый wave, или видео в виде последовательности .tga? =)
ID_Daemon Автор
Речь не о том, «пожаты» они сами по себе или нет. Я просто сказал, что есть игры, которые пакуют всё. Для примера возьмем такую известную серию как Doom/Quake. Все ресурсы, включая звук, одной кучей упакованы в zip-архив.
Leopotam
Внешняя память всегда самая медленная — практически всегда быстрее прочитать небольшой блок упакованных данных одним куском и потом распаковать его в значительно больший объем данных для использования в оперативной памяти.