Формат файлов *.object(формат объектов SDK)

Материал из S.T.A.L.K.E.R. Inside Wiki.

Перейти к: навигация, поиск

Формат разобрал excid

Содержание

О формате

Формат *.object используется в качестве основного формата хранения моделей на этапе редактирования (включая экспорт из Maya или 3ds Max и хранение моделей до компиляции уровня)

Описание структуры

Формат бинарный. Файл состоит из вложенных друг в друга блоков. Весь файл представляет собой единый блок.

Структура блока

Блок имеет 3 обязательные части:

ЧастьТип(размер)Подробнее
Идентификатор типа блока(4)2 байта идентификатора и 2 нулевых байта
Размер блокаuint(4)без учета этих частей — только то, что идет дальше
Данные(Размер блока)Данные могут быть представлены вложенными блоками

Типы данных

Особое внимание стоит обратить на то, как хранятся строки: они нуль-терминальные, то есть в конце обязательно содержат нулевой байт.

Структура

В заголовке последующих пунктов в скобках содержатся идентификаторы типа блока в шестнадцатиричной форме, при этом байты представлены в обратном порядке (то есть так, как числа задаются в исходниках), поэтому идентификатор 0x0912 в файле будет выглядеть как 09 12 00 00.

Файл (0x7777)

Неизвестные данные (0x0900)

Возможно, это версия.

НазваниеТип(размер)ЗначениеПодробнее
Неизвестно(2)0x10 0x00

Пользовательские информация — User Data (0x0912)

В редакторе Game options > User Data.

НазваниеТип(размер)ЗначениеПодробнее
ДанныестрокаПроизвольная строка

Уровень детализации — LOD (0x0925)

В редакторе LOD > Reference.

НазваниеТип(размер)ЗначениеПодробнее
СсылкастрокаПуть к модели, содержащей следующий уровень детализации

Тип объекта — Object Type (0x0903)

В редакторе Object Type.

НазваниеТип(размер)ЗначениеПодробнее
Тип(4)Значение 0x00 для статической модели (тип Static)

Данные о геометрии — Geometry (0x0910)

В редакторе Geometry. Все представленные ниже данные описывают 1 подобъект.

Неизвестные данные (0x1000)

НазваниеТип(размер)ЗначениеПодробнее
Неизвестно(2)0x11 0x00

Название подобъекта — Name (0x1000)

НазваниеТип(размер)ЗначениеПодробнее
Названиестрока

Ограничивающий параллелепипед — Bounding Box (0x1004)

В редакторе Transform > BBox Min/Max

НазваниеТип(размер)ЗначениеПодробнее
Минимумfloat(4)[3]Минимальные значения вершин по x, y, z
Максимумfloat(4)[3]Максимальные значения вершин по x, y, z

Неизвестные данные (0x1002)

НазваниеТип(размер)ЗначениеПодробнее
Неизвестно(1)0x05

Неизвестные данные (0x1010)

НазваниеТип(размер)ЗначениеПодробнее
Неизвестно(8)0x00Все нули

Вершины — Vertices (0x1005)

НазваниеТип(размер)ЗначениеПодробнее
Количество вершин nuint(4)
Координатыfloat(4)[n * 3]Координаты x, y, z для каждой вершины

Грани — Faces (0x1006)

НазваниеТип(размер)ЗначениеПодробнее
Количество граней muint(4)
Координатыuint(4)[m * 6]Троки пар индекс вершины + индекс текстурной координаты

Группы сглаживания — Smoothing Groups (0x1013)

НазваниеТип(размер)ЗначениеПодробнее
Группыuint(4)[m]32-битная маска групп сглаживания для каждой грани

Словарь текстурных координат — UVs map (0x1008)

Логика формирования и назначение этого и блока «Текстурные координаты» доконца не понятна. Предположительный вариант представлен ниже.

НазваниеТип(размер)ЗначениеПодробнее
Количество записей kuint(4)
Данные(9)[k]Предположительная структура в следующей таблице


НазваниеТип(размер)ЗначениеПодробнее
Неизвестноbyte(1)0x1
Индекс таблицы текстурных координатuint(4)0x0 или 0x1Возможно, только первый байт содержит эти данные,
остальные выполняют другие функции
Встречались «некорректные» данные (например, 0x1 0x90 0xdb 0x11 0x7), но они не использовались
Индекс текстурных координатыuint(4)0x0 или 0x1Индекс в таблице, определяемой предыдущим значением.

Материалы объекта — Object Materials (0x1009)

НазваниеТип(размер)ЗначениеПодробнее
Количество материалов pushort(2)
Материалы[p]Cтруктура в следующей таблице


НазваниеТип(размер)ЗначениеПодробнее
Название материаластрока
Количество граней quint(4)Количество граней, имеющих этот материал
Индексы гранейuint(4)[q]

Текстурные координаты — UVs (0x1008)

Количество таблиц, которое встречалось в тестовых файлах — 2.

НазваниеТип(размер)ЗначениеПодробнее
Количество таблиц tuint(4)0x2
Таблицы[t]Структура в следующей таблице


НазваниеТип(размер)ЗначениеПодробнее
НеизвестнострокаTexture
Неизвестноubyte(1)0x2Возможно, количество компонентов в текс. координате?
Номер таблицыushort(1)
Количество текстурных координат suint(4)
Текстурные координатыfloat(4)[s * 2]Пары значения текстурных координат u и v
Неизвестноuint(4)[s]Какие-то индексы, не превышающие s
Неизвестно
(только для второй таблицы)
uint(4)[s]Какие-то индексы, не превышающие s, отсорированные по возрастанию


Материалы — Materials (0x0907)

НазваниеТип(размер)ЗначениеПодробнее
Количество материалов ruint(4)
Материалы[r]Структура в следующей таблице


НазваниеТип(размер)ЗначениеПодробнее
Названиестрока
Характеристика для движкастрокаНапример, default
Характеристика для компиляторастрокаНапример, default
Характеристика для игрыстрокаНапример, default
Путь к текстурестрока
НеизвестнострокаTextureЗначение Texture используется в блоке
Текстурные координаты — UVs (0x1008)
Флагиuint(4)0x1, если материал двустронний, иначе 0x0
Неизвестно(4)0x12 0x1 0x0 0x0 0x1 0x0 0x0 0x0


Автор — Author (0x0907)

НазваниеТип(размер)ЗначениеПодробнее
СоздательстрокаВид \\компьютер\пользователь (например, \\NAPALI\excid)
Дата создания(4)
Последний модифицирующийстрокаВид \\компьютер\пользователь (например, \\NAPALI\excid)
Дата модификации(4)


Скрипт разбора файла

Написан на Python. Не реализован полностью, завершение не планируется, так как свою миссию он выполнил.
Если запускать из Blender, то импортирует объект (без материалов).
Не рекомендуется запускать для больших файлов, так как выводится вся информация из файла.

Код

#                                           #
# XRay Engine (S.T.A.L.K.E.R.) object #
# test import plugin for Blender #
# #
# Anton 'excid' Gorenko #
# excid@mail.ru #
# #
# (2007 June) #
# #
 
from struct import *
import datetime
 
useBlender = True
try:
from Blender import *
from Blender.Mathutils import *
except:
useBlender = False
 
 
f = open('X:\\rawdata\\objects\\detail\\det_list_05.object', 'rb')
s = f.read()
f.close()
 
 
def parseMeshData(s):
 
p = 0
print '\nunknown block =', hex(int(unpack('I', s[p : p + 4])[0]))
p += 4
size = unpack('I', s[p : p + 4])[0]
print 'unknown block size =', size
p += 4
print 'unknown data =', map(hex, unpack('%dB' % (size,), s[p : p + size]))
p += size
 
print '\nname block =', hex(int(unpack('I', s[p : p + 4])[0]))
p += 4
nameSize = unpack('I', s[p : p + 4])[0]
print 'name block size =', nameSize
p += 4
name = unpack('%ds' % (nameSize,), s[p : p + nameSize])[0][:-1]
p += int(nameSize)
print 'name =', name
 
if useBlender:
obj = Object.New('Mesh', name)
mesh = Mesh.New(name)
obj.link(mesh)
scene = Scene.GetCurrent()
scene.objects.link(obj)
 
print '\nbbox block =', hex(int(unpack('I', s[p : p + 4])[0]))
p += 4
print 'bbox block size =', unpack('I', s[p : p + 4])[0]
p += 4
print 'bbox min = ', unpack('3f', s[p : p + 12])
p += 12
print 'bbox max = ', unpack('3f', s[p : p + 12])
p += 12
 
print '\nunknown block =', hex(int(unpack('I', s[p : p + 4])[0]))
p += 4
size = unpack('I', s[p : p + 4])[0]
print 'unknown block size =', size
p += 4
print 'unknown data =', map(hex, unpack('%dB' % (size,), s[p : p + size]))
p += size
 
print '\nunknown block =', hex(int(unpack('I', s[p : p + 4])[0]))
p += 4
size = unpack('I', s[p : p + 4])[0]
print 'unknown block size =', size
p += 4
print 'unknown data =', map(hex, unpack('%dB' % (size,), s[p : p + size]))
p += size
 
print '\nvertices block =', hex(int(unpack('I', s[p : p + 4])[0]))
p += 4
print 'vertices block size =', unpack('I', s[p : p + 4])[0]
p += 4
verticesCount = unpack('I', s[p : p + 4])[0]
p += 4
print 'vertices count =', verticesCount
for i in range(verticesCount):
coords = unpack('3f', s[p : p + 12])
print 'vertex%d =' % (i,), coords
p += 12
 
if useBlender:
mesh.verts.extend([coords])
 
print '\ntriangles block =', hex(int(unpack('I', s[p : p + 4])[0]))
p += 4
print 'triangles block size =', unpack('I', s[p : p + 4])[0]
p += 4
 
trianglesCount = unpack('I', s[p : p + 4])[0]
p += 4
print 'triangles count =', trianglesCount
 
faces = []
for i in range(trianglesCount):
vertices = unpack('6I', s[p : p + 24])
print 'triangle%d =' % (i,), vertices
p += 24
 
faces.append(vertices)
 
print '\nsmoothgroups block =', hex(int(unpack('I', s[p : p + 4])[0]))
p += 4
size = unpack('I', s[p : p + 4])[0]
p += 4
print 'smoothgroups block size =', size
for i in range(size / 4):
x = unpack('I', s[p : p + 4])[0]
print 'triangle%d =' % (i,), hex(int(x))
p += 4
 
print '\nuv map block =', hex(int(unpack('I', s[p : p + 4])[0]))
p += 4
size = unpack('I', s[p : p + 4])[0]
p += 4
print 'uv map block size =', size
count = unpack('I', s[p : p + 4])[0]
p += 4
print 'count =', count
 
layerIndices = []
uvIndices = []
for i in range(count):
unknown = unpack('5B', s[p : p + 5])
p += 5
 
uvIndex = int(unpack('I', s[p : p + 4])[0])
p += 4
 
print 'uv index =', map(hex, unknown), uvIndex
 
layerIndices.append(unknown[1])
uvIndices.append(uvIndex)
 
 
print '\nmaterials block =', hex(int(unpack('I', s[p : p + 4])[0]))
p += 4
size = unpack('I', s[p : p + 4])[0]
p += 4
print 'materials block size =', size
materialsCount = unpack('H', s[p : p + 2])[0]
p += 2
print 'materials count =', materialsCount
 
for i in range(materialsCount):
materialName = ''
b = unpack('B', s[p : p + 1])[0]
p += 1
while b != 0:
materialName = materialName + chr(b)
b = unpack('B', s[p : p + 1])[0]
p += 1
print 'material%d name =' % (i,), materialName
 
trianglesCount = unpack('I', s[p : p + 4])[0]
p += 4
print 'triangles count =', trianglesCount
 
print 'triangles indices =', map(int, unpack('%dI' % (trianglesCount,), s[p : p + 4 * trianglesCount]))
p += 4 * trianglesCount
 
print '\ntexcoords block =', hex(int(unpack('I', s[p : p + 4])[0]))
p += 4
size = unpack('I', s[p : p + 4])[0]
p += 4
print 'texcoords block size =', size
uvTablesCount = unpack('I', s[p : p + 4])[0]
p += 4
print 'uv tables count =', uvTablesCount
 
 
uvs = []
for i in range(uvTablesCount):
currentUv = []
chanelName = ''
b = unpack('B', s[p : p + 1])[0]
p += 1
while b != 0:
chanelName = chanelName + chr(b)
b = unpack('B', s[p : p + 1])[0]
p += 1
print 'name =', chanelName
 
x = unpack('B', s[p : p + 1])[0]
p += 1
print 'unknown =', x
layerIndex = unpack('H', s[p : p + 2])[0]
p += 2
print 'layer index =', layerIndex
count = unpack('I', s[p : p + 4])[0]
p += 4
print 'uvs count =', count
 
for j in range(count):
uv = unpack('2f', s[p : p + 8])
print 'uv%d =' % (j,), uv
p += 8
 
currentUv.append(uv)
uvs.append(currentUv)
 
for j in range(count):
x = unpack('I', s[p : p + 4])[0]
print 'index%d =' % (j,), int(x)
p += 4
 
i = 0
while len(s) > p:
x = unpack('I', s[p : p + 4])[0]
print 'unknown index%d =' % (i,), int(x)
p += 4
i += 1
 
if useBlender:
faceIndex = 0
for faceInfo in faces:
if faceInfo[4] == 0:
faceInfo = faceInfo[2:] + faceInfo[:2]
mesh.faces.extend(faceInfo[::2])
face = mesh.faces[-1]
 
faceUvs = []
for i in faceInfo[1::2]:
faceUvs.append(Vector(uvs[layerIndices[i]][uvIndices[i]]))
face.uv = faceUvs
 
def parseString(s, p):
string = ''
b = unpack('B', s[p : p + 1])[0]
p += 1
while b != 0:
string = string + chr(b)
b = unpack('B', s[p : p + 1])[0]
p += 1
return string, p
 
 
 
def parseGeometryBlock(s):
print '\ngeometry\n'
p = 0
while p < len(s):
i = unpack('I', s[p : p + 4])[0]
p += 4
dataSize = unpack('I', s[p : p + 4])[0]
print 'mesh%d data size = %d' % (i, dataSize)
p += 4
parseMeshData(s[p : p + dataSize])
p += dataSize
 
 
def parseMaterialBlock(s):
print '\nmaterials\n'
p = 0
materialsCount = unpack('I', s[p : p + 4])[0]
p += 4
print 'materials count =', materialsCount
 
for i in range(materialsCount):
print '\n'
materialName, p = parseString(s, p)
print 'material%d name =' % (i,), materialName
 
engineShader, p = parseString(s, p)
print 'engine shader =', engineShader
 
compilerShader, p = parseString(s, p)
print 'compiler shader =', compilerShader
 
gameMaterial, p = parseString(s, p)
print 'game material =', gameMaterial
 
texturePath, p = parseString(s, p)
print 'texture path =', texturePath
 
texture, p = parseString(s, p)
print 'texture =', texture
 
print 'flags (2 sided, etc) =', hex(int(unpack('I', s[p : p + 4])[0]))
p += 4
 
size = 8
print 'unknown data =', map(hex, unpack('%dB' % (size,), s[p : p + size]))
p += size
 
 
def parseAuthorBlock(s):
print '\nauthor\n'
p = 0
authorName, p = parseString(s, p)
print 'author name =', authorName
 
size = 4
print 'creation date =', map(hex, unpack('%dB' % (size,), s[p : p + size]))
p += size
 
 
modifierName, p = parseString(s, p)
print 'modifier name =', modifierName
 
print 'modification date =', map(hex, unpack('%dB' % (size,), s[p : p + size]))
p += size
 
 
def parseUserDataBlock(s):
print '\nuser data\n'
p = 0
userData, p = parseString(s, p)
print 'user data =', userData
 
 
def parseLODBlock(s):
print '\nlod\n'
p = 0
reference, p = parseString(s, p)
print 'lod reference =', reference
 
 
def parseFlagsBlock(s):
print '\nflags (model type)\n'
p = 0
flags = unpack('I', s[p : p + 4])[0]
print 'model type =', hex(int(flags))
 
 
print '\n' * 3
 
p = 0
header = unpack('I', s[p : p + 4])[0]
print 'header =', hex(int(header))
p += 4
 
dataSize = unpack('I', s[p : p + 4])[0]
print 'data size =', dataSize
p += 4
 
while p < len(s):
print '\n'
print '=' * 79
block = unpack('I', s[p : p + 4])[0]
print 'block =', hex(int(block))
p += 4
 
blockSize = unpack('I', s[p : p + 4])[0]
print 'block size =', blockSize
p += 4
 
if block == 0x0910:
parseGeometryBlock(s[p : p + blockSize])
elif block == 0x0907:
parseMaterialBlock(s[p : p + blockSize])
elif block == 0x0922:
parseAuthorBlock(s[p : p + blockSize])
elif block == 0x0912:
parseUserDataBlock(s[p : p + blockSize])
elif block == 0x0925:
parseLODBlock(s[p : p + blockSize])
elif block == 0x0903:
parseFlagsBlock(s[p : p + blockSize])
else:
print 'unknown data =', map(hex, unpack('%dB' % (blockSize,), s[p : p + blockSize]))
p += blockSize

Результат

header = 0x7777
data size = 1113
 
 
===============================================================================
block = 0x900
block size = 2
unknown data = ['0x10', '0x0']
 
 
===============================================================================
block = 0x912
block size = 1
 
user data
 
user data =
 
 
===============================================================================
block = 0x925
block size = 1
 
lod
 
lod reference =
 
 
===============================================================================
block = 0x903
block size = 4
 
flags (model type)
 
model type = 0x0
 
 
===============================================================================
block = 0x910
block size = 929
 
geometry
 
mesh0 data size = 921
 
unknown block = 0x1000
unknown block size = 2
unknown data = ['0x11', '0x0']
 
name block = 0x1001
name block size = 8
name = Plane10
 
bbox block = 0x1004
bbox block size = 24
bbox min = (-0.089013084769248962, 0.00091872771736234426, -0.05408264324069023
1)
bbox max = (0.064492635428905487, 0.017687048763036728, 0.050194162875413895)
 
unknown block = 0x1002
unknown block size = 1
unknown data = ['0x5']
 
unknown block = 0x1010
unknown block size = 8
unknown data = ['0x0', '0x0', '0x0', '0x0', '0x0', '0x0', '0x0', '0x0']
 
vertices block = 0x1005
vertices block size = 88
vertices count = 7
vertex0 = (-0.0019903033971786499, 0.001169001217931509, 0.0068940594792366028)
vertex1 = (-0.089013084769248962, 0.00091872771736234426, 0.045723527669906616)
vertex2 = (0.006468137726187706, 0.0094316964969038963, 0.050194162875413895)
vertex3 = (-0.039456427097320557, 0.0043633054010570049, -0.039133470505475998)
vertex4 = (0.023728765547275543, 0.0064991358667612076, -0.054082643240690231)
vertex5 = (0.031571760773658752, 0.0060988827608525753, 0.0041843997314572334)
vertex6 = (0.064492635428905487, 0.017687048763036728, -0.038134712725877762)
 
triangles block = 0x1006
triangles block size = 148
triangles count = 6
triangle0 = (0, 2, 1, 1, 2, 0)
triangle1 = (0, 8, 3, 7, 1, 6)
triangle2 = (0, 11, 4, 10, 3, 9)
triangle3 = (5, 14, 6, 13, 4, 12)
triangle4 = (0, 17, 2, 16, 5, 15)
triangle5 = (0, 20, 5, 19, 4, 18)
 
smoothgroups block = 0x1013
smoothgroups block size = 24
triangle0 = 0x1
triangle1 = 0x1
triangle2 = 0x1
triangle3 = 0x1
triangle4 = 0x1
triangle5 = 0x1
 
uv map block = 0x1008
uv map block size = 193
count = 21
uv index = ['0x1', '0x0', '0x0', '0x0', '0x0'] 2
uv index = ['0x1', '0x0', '0x0', '0x0', '0x0'] 1
uv index = ['0x1', '0x0', '0x0', '0x0', '0x0'] 0
uv index = ['0x1', '0x90', '0xdb', '0x11', '0x7'] 12
uv index = ['0x1', '0x18', '0x87', '0x10', '0x7'] 12
uv index = ['0x1', '0x80', '0x8c', '0x10', '0x7'] 12
uv index = ['0x1', '0x1', '0x0', '0x0', '0x0'] 1
uv index = ['0x1', '0x0', '0x0', '0x0', '0x0'] 3
uv index = ['0x1', '0x1', '0x0', '0x0', '0x0'] 0
uv index = ['0x1', '0x1', '0x0', '0x0', '0x0'] 3
uv index = ['0x1', '0x0', '0x0', '0x0', '0x0'] 4
uv index = ['0x1', '0x1', '0x0', '0x0', '0x0'] 2
uv index = ['0x1', '0x1', '0x0', '0x0', '0x0'] 4
uv index = ['0x1', '0x0', '0x0', '0x0', '0x0'] 6
uv index = ['0x1', '0x0', '0x0', '0x0', '0x0'] 5
uv index = ['0x1', '0x1', '0x0', '0x0', '0x0'] 7
uv index = ['0x1', '0x1', '0x0', '0x0', '0x0'] 6
uv index = ['0x1', '0x1', '0x0', '0x0', '0x0'] 5
uv index = ['0x1', '0x1', '0x0', '0x0', '0x0'] 10
uv index = ['0x1', '0x1', '0x0', '0x0', '0x0'] 9
uv index = ['0x1', '0x1', '0x0', '0x0', '0x0'] 8
 
materials block = 0x1009
materials block size = 43
materials count = 1
material0 name = 01 - Default
triangles count = 6
triangles indices = [0, 1, 2, 3, 4, 5]
 
texcoords block = 0x1012
texcoords block size = 294
uv tables count = 2
name = Texture
unknown = 2
layer index = 0
uvs count = 7
uv0 = (0.72911489009857178, 0.70259565114974976)
uv1 = (0.4648970365524292, 0.95080757141113281)
uv2 = (0.55649280548095703, 0.58906811475753784)
uv3 = (0.97081756591796875, 0.88250058889389038)
uv4 = (0.97814416885375977, 0.69620668888092041)
uv5 = (0.75604760646820068, 0.52614188194274902)
uv6 = (0.98893237113952637, 0.51763355731964111)
index0 = 0
index1 = 1
index2 = 2
index3 = 3
index4 = 4
index5 = 5
index6 = 6
name = Texture
unknown = 2
layer index = 1
uvs count = 11
uv0 = (0.72911489009857178, 0.70259565114974976)
uv1 = (0.4648970365524292, 0.95080757141113281)
uv2 = (0.72911489009857178, 0.70259565114974976)
uv3 = (0.97081756591796875, 0.88250058889389038)
uv4 = (0.97814416885375977, 0.69620668888092041)
uv5 = (0.72911489009857178, 0.70259565114974976)
uv6 = (0.5510140061378479, 0.58371180295944214)
uv7 = (0.75604760646820068, 0.52614188194274902)
uv8 = (0.72911489009857178, 0.70259565114974976)
uv9 = (0.75604760646820068, 0.52614188194274902)
uv10 = (0.97814416885375977, 0.69620668888092041)
index0 = 0
index1 = 1
index2 = 0
index3 = 3
index4 = 4
index5 = 0
index6 = 2
index7 = 5
index8 = 0
index9 = 5
index10 = 4
unknown index0 = 1
unknown index1 = 1
unknown index2 = 2
unknown index3 = 2
unknown index4 = 3
unknown index5 = 4
unknown index6 = 4
unknown index7 = 4
unknown index8 = 5
unknown index9 = 5
unknown index10 = 5
 
 
===============================================================================
block = 0x907
block size = 82
 
materials
 
materials count = 1
 
 
material0 name = 01 - Default
engine shader = details\blend
compiler shader = default
game material = default
texture path = det\det_listya
texture = Texture
flags (2 sided, etc) = 0x0
unknown data = ['0x12', '0x1', '0x0', '0x0', '0x1', '0x0', '0x0', '0x0']
 
 
===============================================================================
block = 0x922
block size = 38
 
author
 
author name = \\SUSHKA\cy-27
creation date = ['0xf', '0x28', '0x98', '0x43']
modifier name = \\SUSHKA\cy-27
modification date = ['0xf', '0x28', '0x98', '0x43']
Личные инструменты
Другие места