SOA forever!

Солдаты Анархии

Информация о пользователе

Привет, Гость! Войдите или зарегистрируйтесь.


Вы здесь » Солдаты Анархии » Все о Солдатах » Изучение структуры diff3d формата


Изучение структуры diff3d формата

Сообщений 1 страница 9 из 9

1

Все об этом загадочном формате 3D моделей. Полное описание позволит создать не только парсеры, но и OpenGL вьюверы. В которых будет возможность детального просмотра структуры (дерево разделов как diff3d-viewer-е, смещения и размеры отдельных блоков с возможностью их редактирования), а также просмотр самой 3D модели и фреймов анимации.
---
То что на данный момент точно известно:

offset $0(0)  size $8(8) - неизвестная цепочка байт, но постоянная
offset $8(8)  size $10(16) - магические байты, именно такой их размер и содержание подтверждаются как в sоa.еxe так и в diff3dviеwer.еxe
offset $18(24) size $4(4) - dword смещения начала таблицы ресурсов
offset $1С(28) size $4(4) - dword размера таблицы ресурсов
---
На этом изученная часть заканчиватся и начинается условно-изученная. Скорее всего размер каждого блока $10(16) байт, последний dword с конца - это размер ресурса, предпоследний dword это смещение_начала_блока_ресурса+Таинственный_коэффициент, первый word тип ресурса (0 - свиток, 2 - меш красный кубик, 3 - неясно что, текстура или анимация)

Отредактировано <SKAITER> (2019-09-28 17:58:18)

0

2

Немного исходного кода diff3d-вьювера, навряд ли он прольет свет на истинную структуру файлов моделей но все же :

Код:
Код, видимо на си плюс плюс

// diff3dViewerView.cpp : Implementierung der Klasse CDiff3dViewerView
//

#include "stdafx.h"
#include "diff3dViewer.h"

#include "diff3dViewerDoc.h"
#include "diff3dViewerView.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CDiff3dViewerView

IMPLEMENT_DYNCREATE(CDiff3dViewerView, CTreeView)

BEGIN_MESSAGE_MAP(CDiff3dViewerView, CTreeView)
	//{{AFX_MSG_MAP(CDiff3dViewerView)
// HINWEIS - Hier werden Mapping-Makros vom Klassen-Assistenten eingefьgt und entfernt.
//    Innerhalb dieser generierten Quelltextabschnitte NICHTS VERДNDERN!
	//}}AFX_MSG_MAP
	// Standard-Druckbefehle
	ON_COMMAND(ID_FILE_PRINT, CTreeView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_DIRECT, CTreeView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_PREVIEW, CTreeView::OnFilePrintPreview)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CDiff3dViewerView Konstruktion/Destruktion

CDiff3dViewerView::CDiff3dViewerView()
{
	_ImageList.DeleteImageList();
	_ImageList.Attach(HIMAGELIST(ImageList_Create(16,16,ILC_COLOR24,6,50)));

	HBITMAP hBitmap;
	hBitmap = (HBITMAP)LoadImage(GetModuleHandle(NULL),
MAKEINTRESOURCE(IDB_DIFF3DVIEWER_TREE),
IMAGE_BITMAP, 0, 0, LR_LOADTRANSPARENT);

	CBitmap bitmap;
	bitmap.Attach(hBitmap);
	_ImageList.Add(&bitmap, &bitmap);
}

CDiff3dViewerView::~CDiff3dViewerView()
{
}

BOOL CDiff3dViewerView::PreCreateWindow(CREATESTRUCT& cs)
{
	// ZU ERLEDIGEN: Дndern Sie hier die Fensterklasse oder das Erscheinungsbild, indem Sie
	//  CREATESTRUCT cs modifizieren.

	return CTreeView::PreCreateWindow(cs);
}

/////////////////////////////////////////////////////////////////////////////
// CDiff3dViewerView Zeichnen

void CDiff3dViewerView::OnDraw(CDC* pDC)
{
	CDiff3dViewerDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	// ZU ERLEDIGEN: Hier Code zum Zeichnen der ursprьnglichen Daten hinzufьgen
}

/////////////////////////////////////////////////////////////////////////////
// CDiff3dViewerView Drucken

BOOL CDiff3dViewerView::OnPreparePrinting(CPrintInfo* pInfo)
{
	// Standardvorbereitung
	return DoPreparePrinting(pInfo);
}

void CDiff3dViewerView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
	// ZU ERLEDIGEN: Zusдtzliche Initialisierung vor dem Drucken hier einfьgen
}

void CDiff3dViewerView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
	// ZU ERLEDIGEN: Hier Bereinigungsarbeiten nach dem Drucken einfьgen
}

/////////////////////////////////////////////////////////////////////////////
// CDiff3dViewerView Diagnose

#ifdef _DEBUG
void CDiff3dViewerView::AssertValid() const
{
	CTreeView::AssertValid();
}

void CDiff3dViewerView::Dump(CDumpContext& dc) const
{
	CTreeView::Dump(dc);
}

CDiff3dViewerDoc* CDiff3dViewerView::GetDocument() // Die endgьltige (nicht zur Fehlersuche kompilierte) Version ist Inline
{
	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CDiff3dViewerDoc)));
	return (CDiff3dViewerDoc*)m_pDocument;
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CDiff3dViewerView Nachrichten-Handler

void CDiff3dViewerView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint) 
{
	CTreeCtrl& tree = this->GetTreeCtrl();

	tree.DeleteAllItems();

	_hItemMaterials = tree.InsertItem(
TVIF_TEXT|TVIF_PARAM|TVIF_IMAGE|TVIF_SELECTEDIMAGE, 
"MATERIALS",
7, 7, 0, 0, 0, TVI_ROOT, TVI_LAST);
	_hItemObjects = tree.InsertItem(
TVIF_TEXT|TVIF_PARAM|TVIF_IMAGE|TVIF_SELECTEDIMAGE,
"OBJECTS",
7, 7, 0, 0, 0, TVI_ROOT, TVI_LAST);

	if (GetDocument()->_pNode != NULL) {
FillObjects(GetDocument()->_pNode, _hItemObjects);
	}

	for(int i = 0; i < GetDocument()->_Materials.size(); i++) {
CDiff3DLoader::tMaterialMaps& maps = GetDocument()->_Materials[i];

HTREEITEM hItemMaterial = tree.InsertItem(
	TVIF_TEXT|TVIF_PARAM|TVIF_IMAGE|TVIF_SELECTEDIMAGE,
	"Material",
	5, 5, 0, 0, 0, _hItemMaterials, TVI_LAST);

for(int j = 0; j < maps.size(); j++) {
	HTREEITEM hItemMap = tree.InsertItem(
TVIF_TEXT|TVIF_PARAM|TVIF_IMAGE|TVIF_SELECTEDIMAGE,
"Map", 
6, 6, 0, 0, 0, hItemMaterial, TVI_LAST);

	tstring strMap;

	CDiff3DLoader::tMaterialMap& map = maps[j];

	strMap = "Effect: ";
	if (map.diff3DMaterialMap.dwEffect == 0) {
strMap += "Solid ";
	}
	if ((map.diff3DMaterialMap.dwEffect&DIFF3D_MAPEFFECT_ALPHA)
== DIFF3D_MAPEFFECT_ALPHA) {
strMap += "Alpha ";
	}
	if ((map.diff3DMaterialMap.dwEffect&DIFF3D_MAPEFFECT_ALPHAADD)
== DIFF3D_MAPEFFECT_ALPHAADD) {
strMap += "Additive ";
	}
	tree.InsertItem(TVIF_TEXT|TVIF_PARAM|TVIF_IMAGE|TVIF_SELECTEDIMAGE,
strMap.c_str(), 
6, 6, 0, 0, 0, hItemMap, TVI_LAST);

	strMap = "Texture: ";
	strMap += map.strTexture;

	tree.InsertItem(TVIF_TEXT|TVIF_PARAM|TVIF_IMAGE|TVIF_SELECTEDIMAGE,
strMap.c_str(), 
6, 6, 0, 0, 0, hItemMap, TVI_LAST);
}
	}

	tree.Expand(_hItemMaterials, TVE_EXPAND);
	tree.Expand(_hItemObjects, TVE_EXPAND);
}

void CDiff3dViewerView::OnInitialUpdate() 
{
	CTreeCtrl& tree = this->GetTreeCtrl();
	SetWindowLong(tree,GWL_STYLE,
GetWindowLong(tree,GWL_STYLE)|TVS_HASLINES|TVS_LINESATROOT|TVS_HASBUTTONS);

	tree.SetImageList(&_ImageList,TVSIL_NORMAL);

	CTreeView::OnInitialUpdate();
}

void CDiff3dViewerView::FillObjects(CDXA3DObject* pNode, HTREEITEM hParentItem)
{
	HTREEITEM hItem;
	CTreeCtrl& tree = this->GetTreeCtrl();

	{
tstring strObject;
int iImage = 0;
HTREEITEM hInsert = TVI_LAST;

switch (pNode->GetObjectType()) {
case DXA3DOBJ_OBJECT: {
	strObject = "object: ";
	if (pNode->GetName() != NULL) {
strObject += pNode->GetName();
	}
	  }break;
case DXA3DOBJ_NODE: {
	tstring strName;
	strObject = "node: ";
	if (pNode->GetName() != NULL) {
strName = pNode->GetName();
strObject += strName;
	}
	iImage = 1;

	if (strName.length() >= 3) {
if ((strName[0] == 'd') &&
	(strName[1] == 'm') &&
	(strName[2] == 'y')) {
	iImage = 4;
}
	}
	  }break;
case DXA3DOBJ_MESH: {
	strObject = "mesh: ";
	if (pNode->GetName() != NULL) {
strObject += pNode->GetName();
	}
	iImage = 2;
	hInsert = TVI_FIRST;
	  }break;
}

hItem = tree.InsertItem(
	TVIF_TEXT|TVIF_PARAM|TVIF_IMAGE|TVIF_SELECTEDIMAGE,
	strObject.c_str(), 
	iImage, iImage, 0, 0, (DWORD)pNode, hParentItem, hInsert);
	}

	for (int i = 0; i < pNode->GetChildCount(); i++) {
FillObjects(pNode->GetChild(i), hItem);
	}

	{
tstring strAnimation; TCHAR chars[10];

strAnimation = "Animation: ";
if (pNode->GetAnimationTimeHierarchy() > 0) {
	strAnimation += "Hierarchy: ";
	sprintf(chars, "%d ", pNode->GetAnimationTimeHierarchy());
	strAnimation += chars;
}
if (pNode->GetAnimationTime() > 0) {
	strAnimation += "Object: ";
	sprintf(chars, "%d ", pNode->GetAnimationTime());
	strAnimation += chars;
}

if ((pNode->GetAnimationTime() > 0) || (pNode->GetAnimationTimeHierarchy() > 0)) {
	tree.InsertItem(
TVIF_TEXT|TVIF_PARAM|TVIF_IMAGE|TVIF_SELECTEDIMAGE,
strAnimation.c_str(), 
3, 3, 0, 0, 0, hItem, TVI_FIRST);
}
	}

	tree.Expand(hItem, TVE_EXPAND);
}

Отредактировано <SKAITER> (2019-09-28 18:32:20)

0

3

Начало списка Materials:

В таблице ресурсов занимает последнее место, минус $10(16) байт соответственно. Всегда имеет начальный word 3. Значение offset также как и для других блоков это предпоследний dword с конца блока.  Сам список материалов с их названиями располагается по смещению offset плюс $35(53) байт. Перейдя по offset плюс $35(53) попадаем на первый байт количества текстур. Проверил на 10 случайных diff3d, все совпадает. //если НЕ ПРИБАВИТЬ 53 байт к dword смещения указателя списка текстур, то попадем в центр рандомной строки, что довольно странно.

Отредактировано <SKAITER> (2019-09-29 19:07:01)

0

4

Нашел истинное смещение всех Objects и Node. К dword offset добавляем $94(148) и попадаем на первый байт длинны строки (если это название раздела Node) либо на начало таблицы треугольников (если offset блока mesh, красный кубик в diff3dViewere-е).
---
В общем с этими знаниями уже можно написать простенький ридер файлов моделей. Который будет безошибочно распознавать строки начала разделов, первую текстуру (там дальше легко понять алгоритм чтения характеристик и названия последующих), области с мешами.

0

5

Константы смещений оказались верные, и что немаловажно постоянные.
http://s3.uploads.ru/64wVr.png

0

6

Лоу-польная сфера в своем графическом отображении.
http://s9.uploads.ru/jBMPI.png

А это дно конуса. Сверху пcиходелический кaлейдоскоп (из-за лaмерской нaстройки OpenGL??). Но это не главное. Разве такое ровное дно могло бы получиться если бы треугольники побились? если бы они не соответствовали вершинам. Там однозначно были бы прогалы, а само очертание круга с четкими гранями пропало.

http://sg.uploads.ru/O5ksI.png

Отредактировано <SKAITER> (2019-09-30 22:22:40)

0

7

Попробую добавить распознавание текстурных координат и нормалей при конвертировании мешей обратно в .ase. Если все получится то модели будут идентичные тем что в самой игре.
http://s5.uploads.ru/Xlwuz.png

0

8

Разобрался с текстурными вершинами. Только после импорта в редактор надо выделить всю UV сетку, перевернуть сверху вниз и отразить. Я эти все нюансы добавлю в описание вместе с diff3dReader-om.
http://sh.uploads.ru/u5vOY.png

+1

9

Тecтовая версия Diff3dReader-а     -      здесь

+1


Вы здесь » Солдаты Анархии » Все о Солдатах » Изучение структуры diff3d формата