CodeNet / Приложения / Графика / Форматы файлов
CodeNet / Остальное / Форматы файлов
Формат 3DS-файла
Основная идея вот: файл 3DS состоит из блоков (chunks), каждый из которых содержит какие-то полезные данные и, возможно, подблоки. Большинство блоков содержит либо данные, либо подблоки, хотя есть и смешанные блоки. Общий формат каждого блока такой:
смещение | длина | данные |
0 | 2 | идентификатор типа блока, chunk_id |
2 | 4 | длина блока, chunk_len |
4 | chunk_len | данные или подблоки (в зависимости от chunk_id) |
В качестве относительно полного описания конкретного содержимого блоков я бы порекомендовал следующие вещи:
исходники 3DS reader от MRI/Doomsday, читаются они просто великолепно. Скачать можно на
ftp://ftp.cdrom.com/pub/demos/code/3ds/3dsrdr13.zip;3dsinfo.txt от digisnap.
Здесь я приведу лишь частичное описание, достаточное, впрочем, для того, чтобы прочитать из 3DS-файла 3D сцену и информацию о ее (сцены) анимации.
Итак, список идентификаторов типов нужных нам для этого блоков:
CHUNK_MAIN = 0x4D4D; // [-] сцена CHUNK_OBJMESH = 0x3D3D; // [-] всяческие объекты CHUNK_OBJBLOCK = 0x4000; // [+] объект CHUNK_TRIMESH = 0x4100; // [-] trimesh-объект CHUNK_VERTLIST = 0x4110; // [+] список вершин CHUNK_FACELIST = 0x4120; // [+] список граней CHUNK_FACEMAT = 0x4130; // [+] материалы граней CHUNK_MAPLIST = 0x4140; // [+] текстурные координаты CHUNK_TRMATRIX = 0x4160; // [+] матрица перевода CHUNK_CAMERA = 0x4700; // [+] объект-камера CHUNK_MATERIAL = 0xAFFF; // [-] материал CHUNK_MATNAME = 0xA000; // [+] название материала CHUNK_TEXTURE = 0xA200; // [-] текстура материала CHUNK_MAPFILE = 0xA300; // [+] имя файла текстуры HUNK_KEYFRAMER = 0xB000; // [-] информация об анимации CHUNK_TRACKINFO = 0xB002; // [-] поведение объекта CHUNK_TRACKOBJNAME = 0xB010; // [+] название этого объекта CHUNK_TRACKPIVOT = 0xB013; // [+] центр вращения объекта CHUNK_TRACKPOS = 0xB020; // [+] траектория объекта CHUNK_TRACKROTATE = 0xB021; // [+] траектория вращения // объекта CHUNK_TRACKCAMERA = 0xB003; // [-] поведение камеры CHUNK_TRACKFOV = 0xB023; // [+] поведение FOV камеры CHUNK_TRACKROLL = 0xB024; // [+] поведение roll камеры CHUNK_TRACKCAMTGT = 0xB004; // [-] поведение "цели" камеры
Конкретные данные содержат лишь блоки, отмеченные плюсом, остальные блоки состоят лишь из подблоков и их нам надо различать лишь потому, что нужные нам блоки данных - подблоки этих остальных. То есть, скажем, CHUNK_OBJMESH нам надо знать из-за того, что каждый объект в сцене описывается блоком CHUNK_OBJBLOCK, который появляется только как подблок CHUNK_OBJMESH, и просто игнорировать весь CHUNK_OBJMESH из-за этого нельзя. Кроме того, они задают структуру - например, все данные, что относятся к текущему блоку CHUNK_OBJBLOCK, относятся к текущему объекту, а подблоки этого блока уже могут быть разбросаны как угодно.
А теперь - относительно полное описание того, какие данные содержатся в каждом из блоков. Будут использоваться следующие обозначения:
char[] ASCIIZ-строка (ASCII-строка, оканчивающаяся нулем) byte 8-битное беззнаковое целое число word 16-битное беззнаковое целое число dword 32-битное целое число float 32-битное число с плавающей запятой vector float x,z,y
Здесь (в самой последней строчке) опечатки нет! В файле 3DS везде изменен порядок следования y и z; то есть в файле данных ось y смотрит вглубь экрана, а ось z - вверх. Несмотря на то, что в самой 3D Studio ось y смотрит как раз вверх, а z - вдаль.
Блок: | CHUNK_VERTLIST | ||||||||||||||||||||||||||||||||
Данные: |
список вершин текущего объекта
| ||||||||||||||||||||||||||||||||
Формат: | word num; // число вершин vector vertices[num]; // координаты каждой из вершин | ||||||||||||||||||||||||||||||||
Блок: | CHUNK_FACELIST | ||||||||||||||||||||||||||||||||
Данные: |
список граней текущего объекта
| ||||||||||||||||||||||||||||||||
Формат: | word num; // число граней struct { // word v0; // номер первой вершины грани word v1; // номер второй вершины грани word v2; // номер третьей вершины грани word flags; // флаги грани } faces[num]; // собственно список граней | ||||||||||||||||||||||||||||||||
Блок: | CHUNK_FACEMAT | ||||||||||||||||||||||||||||||||
Данные: |
название материала и список тех граней объекта, которым назначен
этот материал; таких блоков может быть несколько (грани с разными
материалами в одном объекте), а может вообще не быть, если объекту
материалы вообще не назначены (нетекстурированный объект)
| ||||||||||||||||||||||||||||||||
Формат: | char name[]; // название материала word num; // число граней из этого материала word face_nums[num]; // список номеров граней из этого // материала | ||||||||||||||||||||||||||||||||
Блок: | CHUNK_MAPLIST | ||||||||||||||||||||||||||||||||
Данные: |
текстурные координаты вершин текущего объекта
| ||||||||||||||||||||||||||||||||
Формат: | word num; // число вершин struct { // float u; // координата текстуры U // (по горизонтали) float v; // координата текстуры V // (по вертикали) } texcoords[num]; // собственно список текстурных // координат Текстурные координаты задаются в диапазоне 0..1. Точка с U=0, V=0 - левый верхний край текстуры; U=1, V=1 - правый нижний; U=0.5, V=0.5 - центр текстуры. | ||||||||||||||||||||||||||||||||
Блок: | CHUNK_TRMATRIX | ||||||||||||||||||||||||||||||||
Данные: |
содержит матрицу перевода объекта в некое абстрактное начальное
состояние; в то, что было первоначально смоделировано. Требуется
для корректного отображения анимации: дело в том, что все объекты
в файле хранятся по состоянию на нулевой кадр, а анимация записана
по отношению к "начальным" моделям. Т.е. при отображений нулевого
кадра эта матрица не нужна, а при отображении всего набора кадров
надо будет сначала перевести объекты в "начальное" состояние с
помощью этой самой матрицы перевода и применять все преобразования
(перемещения, повороты, etc) именно к "начальным" объектам.
| ||||||||||||||||||||||||||||||||
Формат: | float rotmatrix[3][3]; // матрица поворота vector offset; // смещение начального объекта Для перевода объекта в "начальное" состояние надо сначала сдвинуть его назад, то есть на вектор -offset (НЕ на offset), а потом применить матрицу поворота rotmatr. Матрица записана построчно. Не забудьте - в ней y и z тоже везде обменены местами! | ||||||||||||||||||||||||||||||||
Блок: | CHUNK_MATNAME | ||||||||||||||||||||||||||||||||
Данные: |
название материала
| ||||||||||||||||||||||||||||||||
Формат: | char[] name; // название материала | ||||||||||||||||||||||||||||||||
Блок: | CHUNK_MAPFILE | ||||||||||||||||||||||||||||||||
Данные: |
имя файла с текстурой
| ||||||||||||||||||||||||||||||||
Формат: | char[] filename; // имя файла с текстурой | ||||||||||||||||||||||||||||||||
Блок: | CHUNK_TRACKOBJNAME | ||||||||||||||||||||||||||||||||
Данные: |
название объекта, информация о поведении которого задается в
текущем блоке CHUNK_TRACKINFO
| ||||||||||||||||||||||||||||||||
Формат: | char[] name; // название объекта word flags[2]; // флаги word parent; // номер объекта-родителя Поле parent используется для построения иерархической структуры; дерева объектов. Каждому объекту присваивается его порядковый номер при следовании в файле, поле parent выставляется в -1, если у данного объекта нет родителя. Вот пример. объект | номер | parent --------+-------+-------- A | 0 | -1 B | 1 | 0 A C | 2 | 1 +---------+----+ D | 3 | 2 B K N E | 4 | 1 +----+----+ + + F | 5 | 4 C E H L O G | 6 | 5 + + + + + H | 7 | 1 D F I M P I | 8 | 7 + + J | 9 | 8 G J K | 10 | 0 L | 11 | 10 M | 12 | 11 N | 13 | 0 O | 14 | 13 P | 15 | 14 Насколько я понял, дерево используется следующим образом: если к какому-то узлу дерева применяется преобразование, то оно же автоматически применяется и ко всем узлам, "растущим" из этого. То есть, если объект B в нашем примере есть рука, а объекты C, D, E, F, G, H, I, J - пальцы, то при повороте руки пальцы должны повернуться автоматически, вместе с рукой. В результате блок CHUNK_TRACKROTATE для пальцев может быть пустым, а пальцы будут вращаться вместе с рукой. | ||||||||||||||||||||||||||||||||
Блок: | CHUNK_TRACKPIVOT | ||||||||||||||||||||||||||||||||
Данные: |
координаты центра вращения объекта
| ||||||||||||||||||||||||||||||||
Формат: | vector pivotpoint; // координаты центра вращения Центр вращения - это как раз та точка "начального" объекта, через которую надо будет провести ось вращения, задающуюся в блоке CHUNK_TRACKROTATE. | ||||||||||||||||||||||||||||||||
Блок: | CHUNK_TRACKPOS | ||||||||||||||||||||||||||||||||
Данные: |
траектория объекта, заданная ключевыми значениями положения объекта
| ||||||||||||||||||||||||||||||||
Формат: | word flags; // флаги byte unknown[8]; // dword num; // число ключевых значений struct { // dword frame; // кадр данного ключевого значения word splineflags; // флаги сплайна float[] splineinfo; // параметры сплайна (кол-во и тип // зависит от значения splineflags) vector pos; // положение объекта } keys[num]; // собственно ключевые значения |
Теперь к вопросу о сплайнах и их параметрах. Всего может быть до пяти разных параметров сплайна, появление каждого из них задается каким-то битом в поле splineflags:
установлен бит 0: следует параметр "tension"
установлен бит 1: следует параметр "continuity"
установлен бит 2: следует параметр "bias"
установлен бит 3: следует параметр "ease to"
установлен бит 4: следует параметр "ease from"
То есть при чтении флагов надо последовательно тестировать каждый бит и, если он установлен, читать соответствующий параметр; если не установлен, значит, параметр равен нулю. 3D Studio использует сплайны Кочанека-Бартельса (Kochanek-Bartels) для интерполяции положения и поворотов, при этом повороты вдобавок представляются в форме кватернионов, в ней же и интерполируются.