wt-tools
wt-tools copied to clipboard
GRP Files?
I'd love to be able to pull a high-res model out so I can texture it properly.
I'll try to extract models, but it be faster if i obtain some model file examples.
beach_tank_trap_beton_d_skeleton
beach_tank_trap_beton_d
beach_tank_trap_beton_w_skeleton
beach_tank_trap_beton_w
Awesome! The CDK has some sample models that they include but I'm not sure if they're in their engine's format just decrypted or if they're straight from say Max or Maya...
Файлы .grp
Что мне удалось узнать:
struct GRPHeader { DWORD Signature; // сигнатура, всегда GRP2 DWORD OffsetToIndexTable; // смещение к таблице каких-то индексов. корректируется на +16 DWORD OffsetToIndexTableEnd; // смещение конца вышеуказанной таблицы индексов корректируется на +16 DWORD DataSize; // размер массива данных пакета, File size - 16 };
Далее идут три таблицы типа
struct TableDescriptor { DWORD Offset; // смещение от начала файла DWORD Count; // число элементов };
Первая - к таблице имён, элементы которой указывают на строки типа cstring.
Вторая - к таблице описателей собственно данных. Описатели имеют тип:
struct DataDescriptor { DWORD Type; // похоже, что тип содержимого DWORD Offset; // смещение DWORD ID; // идентификатор };
Третья - к описателям, судя по всему, тех же данных. Имеют тип:
struct tagUnknown { DWORD Type; // вероятно, тип содержимого WORD Index1; // индексы WORD Index2; // DWORD Unknown2; // что-то неясное, часто == 0 DWORD Unknown3; // };
После - сами таблицы имен и описателей. Ну а далее - индексы, смещение на которые указано в заголовке и собственно сами сериализованные данные.
Вопрос в чем: количество имен в пакете часто не совпадает с количеством блоков данных. Резонно сделать вывод, что каждый элемент содержимого, идентифицируемый именем, состоит из двух или более блоков данных, хранящихся в пакете. Так вот интересно, по какому принципу собирать эти данные? Блок типа _skeleton (0x56F81B6D)
Вероятно содержит скелет объекта. Начинается с заголовка
struct skeletonHeader { DWORD size; // размер блока DWORD num; // количество узлов };
Узлы имеют следующий формат
struct skeletonNode { float matrix1[4][4]; // матрица float matrix2[4][4]; // матрица DWORD flags[8]; // что-то неясное, часто == 0, 6 элемент всегда и 4 иногда не равны 0 };
Затем следует таблица из num имён узлов в формате cstring. Блоки геометрии (0xB4B7D9C4)
Содержат информацию о геометрии объекта. Состоят, вероятно, из трёх частей. Заголовок
Начинаются с заголовка
struct gHeader { DWORD unknown; // неизвестно, похоже на тип содержимого. обычно 0x38, 0x48, 0x58, 0x68, 0x78, 0x88, 0x98 uint32 block1_num; // количество элементов в первой части uint32 block2_num; // количество элементов во второй части uint32 block3_num; // количество элементов в третьей части DWORD flags; // разные флаги }
Блок с именами
За заголовком следует блок с именами
struct gNamesTable { DWORD size; // размер данных блока (размер блока - 4) DWORD offset; // смещение до начала таблицы указателей DWORD num; // количество имён DWORD rsvd[2]; // неизвестно cstring names[num]; // сами имена DWORD pointers[num]; // указатели на имена (смещение от начала блока имён) }
Сжатые данные
Если установлен флаг 0x00000040 в заголовке, то далее следуют данные, сжатые алгоритмом lzma. К сожалению, размер сжатых данных не прописан нигде(?), поэтому конец сжатого блока можно отловить по сигнатуре «\x00\x00\x00\x00». которая находится в пяти байтах от конца блока. К тому же, заголовок lzma не содержит информации о размере несжатых данных. В данный момент при распаковке приходится вписывать 8 байтное значение -1 (0xFFFFFFFFFFFFFFFF) после первых 5 байтов сжатого блока. Неизвестный блок
Далее следует неизвестный блок. Начинается с заголовка
struct unknownHeader { uint32 dataOffset; // смещение до блоков данных uint32 num; // количество блоков данных (block1_num в заголовке) uint32 unknown[2]; // неизвестно uint32 dataSize; // размер блока }
Затем до dataOffset следуют неизученные данные. Начиная с dataOffset находится num неизученных блоков по 168 байт каждый.
Завершается блок 36 неизученными байтами. Геометрические данные
Затем следует блок с геометрическими данными. Начинается с заголовка из block2_num элементов
struct gGeometry { uint32 vertices_num; // количество вершин uint32 vertice_format; // формат хранения вершин uint32 indices_size; // размер данных об индексах (количество индексов) uint32 indices_format; // формат хранения индексов uint32 unknown[4]; // неизвестно }
Вершины
Далее хранится информация о вершинах.
Если формат 0x00000010, размер данных о вершине равен 16 байтам и координаты хранятся в приведённом виде x' = x / 32767.0
struct gVertex { uint16 x; // координата x uint16 y; // координата y uint16 z; // координата z uint16 unknown[5]; // неизвестно }
Если формат 0x00000020, размер данных о вершине равен 32 байтам
struct gVertex { float x; // координата x float y; // координата y float z; // координата z float unknown[5]; // неизвестно }
Индексы
Далее хранится информация о индексах. Если формат 0x00000000, размер индекса равен 2 байтам Информация о группах примитивов
Затем идет блок данных с информацией о группах полигонов. Начинается с заголовка
struct gGroupsHeader { uint32 size; // размер заголовка uint32 num; // количество групп BYTE unknown[size-2]; // неизвестно }
Далее следуют num неизвестных блоков по 16 байт каждый.
После них находится неизвестный блок формата
struct gUnknown { uint32 size; // количество следующих данных BYTE unknown[size]; // неизвестно }
Затем хранится сама информация о группах.
Вначале идет непонятная структура, вероятно описатель подгрупп.
struct gUnknown { uint32 size; // количество следующих данных BYTE unknown[size-4]; // неизвестно }
Количество подгрупп можно подсчитать как N = ( size - 0x20 ) / 0x10.
Затем ещё одна неизвестная структура
struct gUnknown { uint32 size; // количество следующих данных BYTE unknown[size+8]; // неизвестно }
Далее следуют несколько (в зависимости от типа) блоков по 88 байт
struct gGroupInfo { BYTE unknown[72]; // неизвестно uint32 first_vertex; // номер первой вершины uint32 vertex_num; // количество вершин uint32 first_indice; // номер первого индекса uint32 faces_num; // количество граней }
Good find! I love it when I can be left to feel illiterate. :D
I'm sorry, but I do not speak English
:smile: :+1:
Besides, I do not know how to use GitHub. I have a script in PHP, which is trying to pull model. But it is in the initial state.
Looks like more complicated than extracting files from archives, huh :-)
Github formatting :)
struct GRPHeader {
DWORD Signature; // сигнатура, всегда GRP2
DWORD OffsetToIndexTable; // смещение к таблице каких-то индексов. корректируется на +16
DWORD OffsetToIndexTableEnd; // смещение конца вышеуказанной таблицы индексов корректируется на +16
DWORD DataSize; // размер массива данных пакета, File size - 16
};
struct TableDescriptor {
DWORD Offset; // смещение от начала файла
DWORD Count; // число элементов
};
struct DataDescriptor {
DWORD Type; // похоже, что тип содержимого
DWORD Offset; // смещение
DWORD ID; // идентификатор
};
struct tagUnknown {
DWORD Type; // вероятно, тип содержимого
WORD Index1; // индексы
WORD Index2; //
DWORD Unknown2; // что-то неясное, часто == 0
DWORD Unknown3; //
};
struct skeletonHeader {
DWORD size; // размер блока
DWORD num; // количество узлов
};
struct skeletonNode {
float matrix1[4][4]; // матрица
float matrix2[4][4]; // матрица
DWORD flags[8]; // что-то неясное, часто == 0, 6 элемент всегда и 4 иногда не равны 0
};
struct gHeader {
DWORD unknown; // неизвестно, похоже на тип содержимого. обычно 0x38, 0x48, 0x58, 0x68, 0x78, 0x88, 0x98
uint32 block1_num; // количество элементов в первой части
uint32 block2_num; // количество элементов во второй части
uint32 block3_num; // количество элементов в третьей части
DWORD flags; // разные флаги
}
struct gNamesTable {
DWORD size; // размер данных блока (размер блока - 4)
DWORD offset; // смещение до начала таблицы указателей
DWORD num; // количество имён
DWORD rsvd[2]; // неизвестно
cstring names[num]; // сами имена
DWORD pointers[num]; // указатели на имена (смещение от начала блока имён)
}
struct unknownHeader {
uint32 dataOffset; // смещение до блоков данных
uint32 num; // количество блоков данных (block1_num в заголовке)
uint32 unknown[2]; // неизвестно
uint32 dataSize; // размер блока
}
struct gGeometry {
uint32 vertices_num; // количество вершин
uint32 vertice_format; // формат хранения вершин
uint32 indices_size; // размер данных об индексах (количество индексов)
uint32 indices_format; // формат хранения индексов
uint32 unknown[4]; // неизвестно
}
struct gVertex {
uint16 x; // координата x
uint16 y; // координата y
uint16 z; // координата z
uint16 unknown[5]; // неизвестно
}
struct gVertex {
float x; // координата x
float y; // координата y
float z; // координата z
float unknown[5]; // неизвестно
}
struct gGroupsHeader {
uint32 size; // размер заголовка
uint32 num; // количество групп
BYTE unknown[size-2]; // неизвестно
}
struct gUnknown {
uint32 size; // количество следующих данных
BYTE unknown[size]; // неизвестно
}
struct gUnknown {
uint32 size; // количество следующих данных
BYTE unknown[size-4]; // неизвестно
}
struct gUnknown {
uint32 size; // количество следующих данных
BYTE unknown[size+8]; // неизвестно
}
struct gGroupInfo {
BYTE unknown[72]; // неизвестно
uint32 first_vertex; // номер первой вершины
uint32 vertex_num; // количество вершин
uint32 first_indice; // номер первого индекса
uint32 faces_num; // количество граней
}
Looks like more complicated than extracting files from archives, huh :-)
The asset viewer may be able to do something with it if it can be extracted.
Or maybe I should mail the devs and say, please give me the the HQ model so I can use it in ZBrush lol...
Or maybe I should mail the devs and say, please give me the the HQ model so I can use it in ZBrush lol...
BTW, u can ask how import models from peoples, who already created new planes on live.warthunder.com, or, perhaps, read there.
What I'm doing is creating a new skin for an existing model that's in game. Usually the problem is that you spend most of the time finding all of the UVs, repainting them finding texture names to export/replace in the BLK etc.
In the CDK they only provide the low LOD version of some of the models. What I'd like to do is export the high quality LOD of a plane, use http://quixel.se/dev/ddo or something to get realtime feedback of my texture painting.
Right now the process is:
- Find model name
- Export texture from Dagor asset viewer
- Discover what UVs are where by editing -> saving -> exporting to TGA/DDS -> alt+tab to WT -> refresh camo in game -> GOTO 1
- Start painting by using above process.
- Export/Compress back to DDS
This equates to hours of lost time for a good reskin.
What I'd like to do is:
- Find model
- Export it and the textures
- Setup DDO scene
- Paint -> Look at DDO preview -> GOTO 1 :smile:
- Export/Compress back to DDS
any work on this? it's been requested in #54 aswell - i can't pay for gamemodels3d because of russia sanctions,
and i refuse to use their sketchy "workaround" using "boosty" which can't even be opened in the uk, blacklisted by the gov't - gotta use a vpn, and even then apparently paypal are blocking a vast ammount of payments to boosty and you must argue your case with them to let the money pass, it's a whole mess, i just want a single plane model ffs
@MasterModeley if you see this can you please reply to my email, it's been a few days with no reply
@Bugz000 unfortunately, I don't think klensy is working on this project at the moment. You may try reaching out to kotiq, he has a similar project, although I'm not sure if it's still active