Render.ru

Geometry Cache. Импорт кэша из Max'a

Konstantin Antipov

Пользователь сайта
Рейтинг
2
#1
Добрый день!
Посчитал реактором ткань в максе (9), сохранил Point Cache и OBJ самой ткани.
Открываю майку(2008 complete), импортнул OBJ, далее говорю Geometry Cache/Import Cache но ничего не выходит, майка ругается: // Error: Selected file has 0 channels and 1 objects are selected. //

Что делать? Как можно еще перенести анимацию?
nCloth не могу юзать.
 

alex_alv

Активный участник
Рейтинг
11
#2
Из макса не импортировал, но сталкивался с проблемами при импорте из Real Flow и из позера. Проблемы решил, написав свою утилиту, которая конвертит некоторые форматы в MA-файл + Geometry Cache. Если проблему решить никто не поможет, пришлите мне на alex_alv@mail.ru Point Cache.
 

alex_alv

Активный участник
Рейтинг
11
#4
#include <windows.h>
#include <stdio.h>
#include <conio.h>


BOOL AskUserFileName(WCHAR * caption,WCHAR * Filter,WCHAR * OutFileName,DWORD fnsize,WCHAR * lpstrDefExt, BOOL Open=TRUE, WCHAR *FileNameWithoutExt=NULL)
{
OPENFILENAME ofn;
BOOL res;
WORD i;

ofn.lStructSize=sizeof(ofn);
ofn.hwndOwner=NULL;
ofn.lpstrFilter=Filter;
ofn.lpstrCustomFilter=NULL;
ofn.nFilterIndex=0;
ofn.lpstrFile=OutFileName;
ofn.nMaxFile=fnsize;
ofn.lpstrFileTitle=NULL;
ofn.lpstrInitialDir=NULL;
ofn.lpstrTitle=caption;
ofn.FlagsEx=0;
ofn.lpstrDefExt=lpstrDefExt;
if(Open)
{
ofn.Flags=OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_LONGNAMES | OFN_EXPLORER;
res=GetOpenFileName(&ofn);
}else
{
ofn.Flags=OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_LONGNAMES | OFN_EXPLORER;
res=GetSaveFileName(&ofn);
}
if((res)&&(FileNameWithoutExt))
{
if(ofn.nFileExtension==0)ofn.nFileExtension=0xFFFF;
for(i=0;i<ofn.nFileExtension;i++)
{
FileNameWithoutExt=OutFileName;
if(OutFileName==0)
{
if(i)
if(FileNameWithoutExt[i-1]==L'.')FileNameWithoutExt[i-1]=0;
return res;
}
}
FileNameWithoutExt=0;
if(i)
if(FileNameWithoutExt[i-1]==L'.')FileNameWithoutExt[i-1]=0;
}
return res;
}

WCHAR SourceFileName[2000]=L"",OBJFileName[2000]=L"";
DWORD PC2Header[8],ExtPos;
float * verts;
BYTE rdbuffer[2000];

HANDLE CreateOBJFile(int FrameNumber)
{
WCHAR gcn[2000];

swprintf_s(gcn,2000,L"%s_%u%s",OBJFileName,FrameNumber,SourceFileName+ExtPos);//-StartFrame+1);
wprintf(L"Creating file %s.\n",gcn);
return CreateFile ( gcn,
GENERIC_WRITE,
FILE_SHARE_READ,
NULL,
CREATE_ALWAYS,
0,
NULL);
}

BOOL ReadFileString(HANDLE hFile,BYTE * buf,DWORD bufsize)
{
DWORD i,wrb;
BYTE b;
BOOL WasRead,n;

if(bufsize==0)return FALSE;
WasRead=FALSE;
i=0;
while(1)
{
ReadFile(hFile,&b,1,&wrb,NULL);
if(wrb)WasRead=TRUE;
if((wrb!=1)||(b==0xA)||(b==0xD))
{
if(i>=bufsize) i=bufsize-1;
buf=0;
if(WasRead)return TRUE;
return FALSE;
}
if(b==9)b=' ';
if(i<bufsize)
{
if(b==' ')
if(i==0)n=FALSE;
else if(buf[i-1]==' ') n=FALSE;
else n=TRUE;
else n=TRUE;
if(n)
{
buf=b;
i++;
}
}
}
}

void main()
{
HANDLE objFile,pc2file,outfile;
DWORD wrb,frame,vsize,vn;

if(!AskUserFileName(L"Open obj-file.",L"OBJ-files\0*.obj\0All files\0*.*\0",SourceFileName,2000,L"OBJ",TRUE))return;
objFile=CreateFile ( SourceFileName,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
0,
NULL);
if(objFile==INVALID_HANDLE_VALUE)
{
wprintf(L"Error opening file.\n");
_getch();
return;
}
SourceFileName[0]=0;
if(!AskUserFileName(L"Open PC2-file.",L"PS2-files\0*.pc2\0All files\0*.*\0",SourceFileName,2000,L"PC2",TRUE))
{
CloseHandle(objFile);
return;
}
pc2file=CreateFile ( SourceFileName,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
0,
NULL);
if(pc2file==INVALID_HANDLE_VALUE)
{
CloseHandle(objFile);
wprintf(L"Error opening file.\n");
_getch();
return;
}
ReadFile(pc2file,PC2Header,32,&wrb,NULL);
if(wrb!=32)
{
CloseHandle(objFile);
CloseHandle(pc2file);
wprintf(L"Error reading PC2 header.\n");
_getch();
return;
}
if((PC2Header[0]!=0x4e494f50)||(PC2Header[1]!=0x43414354)||(PC2Header[2]!=0x00324548)||(PC2Header[4]==0)||(PC2Header[7]==0))
{
CloseHandle(objFile);
CloseHandle(pc2file);
wprintf(L"Incorrect PC2 header format.\n");
_getch();
return;
}
wprintf(L"%i verticies and %i frames in the PC2 file.\n",PC2Header[4],PC2Header[7]);
SourceFileName[0]=0;
vsize=sizeof(float)*PC2Header[4]*3;
verts=(float*)HeapAlloc(GetProcessHeap(),0,vsize);
if(verts==NULL)
{
CloseHandle(objFile);
CloseHandle(pc2file);
wprintf(L"Error allocating memory.\n");
_getch();
return;
}
if(!AskUserFileName(L"Create OBJ sequence",L"OBJ-files\0*.obj\0All files\0*.*\0",SourceFileName,2000,L"obj",FALSE,OBJFileName))
{
HeapFree(GetProcessHeap(),0,verts);
CloseHandle(objFile);
CloseHandle(pc2file);
return;
}
ExtPos=wcsnlen(OBJFileName,2000);
for(frame=1;frame<=PC2Header[7];frame++)
{
outfile=CreateOBJFile(frame);
if(outfile==INVALID_HANDLE_VALUE)
{
HeapFree(GetProcessHeap(),0,verts);
CloseHandle(objFile);
CloseHandle(pc2file);
wprintf(L"Error creating file.\n");
_getch();
return;
}
SetFilePointer(objFile,0,NULL,FILE_BEGIN);
vn=0;
ReadFile(pc2file,verts,vsize,&wrb,NULL);
if(wrb!=vsize)
{
HeapFree(GetProcessHeap(),0,verts);
CloseHandle(objFile);
CloseHandle(pc2file);
wprintf(L"Error reading PC2 file.\n");
_getch();
return;
}
while(ReadFileString(objFile,rdbuffer,2000))
{
if((rdbuffer[0]=='v')&&(rdbuffer[1]==' ')&&(vn<PC2Header[4]))
{
sprintf_s((char*)rdbuffer,2000,"v %f %f %f",verts[vn*3],verts[vn*3+2],verts[vn*3+1]);
vn++;
}
WriteFile(outfile,rdbuffer,strnlen((char*)rdbuffer,2000),&wrb,NULL);
rdbuffer[0]='\n';
WriteFile(outfile,rdbuffer,1,&wrb,NULL);
}

CloseHandle(outfile);
}
HeapFree(GetProcessHeap(),0,verts);
CloseHandle(objFile);
CloseHandle(pc2file);
}
 

alex_alv

Активный участник
Рейтинг
11
#5
Это - исходник программы, которая конвертит OBJ и PointCache2 в сиквенцию OBJ
Консольное приложение под Windows.
Я компилировал в Visual Studio 2008.
Думаю, можно компилировать в другом компиляторе, главное, чтобы тип float имел размер 4 байта.

Конвертацию сиквенции OBJ в MA + Geometry Cache я делал раньше.
 

alex_alv

Активный участник
Рейтинг
11
#7
Небольшая ошибка, связанная с тем, что в Max похоже ось Y - это майская ось Z со знаком минус. Я в программе взял ее со знаком плюс.
Для исправления ошибки надо либо скейл объекта по Y поставить отрицательным, либо в программе строку

sprintf_s((char*)rdbuffer,2000,"v %f %f %f",verts[vn*3],verts[vn*3+2],verts[vn*3+1]);

заменить на строку

sprintf_s((char*)rdbuffer,2000,"v %f %f %f",verts[vn*3],verts[vn*3+2],-verts[vn*3+1]);

На счет формата PC2 на сколько я разобрался:
первые 32 байта - заголовок.
В нем первые 12 байт - строка POINTCACHE2 с нулевым символом на конце.
По смещению +0x10 - целое беззнаковое 32-битное число, определяющее число вершин в каждом кадре кеша.
По смещению +0x1C - целое беззнаковое 32-битное число, определяющее число кадров в кеше.
Остальные поля - не знаю.

После заголовка следуют кадры один за другим подряд. Каждый кадр занимает vn*12 байт, где vn - число вершин (поле +0x10 заголовка)
Каждый кадр содержит координаты всех вершин. Каждая вершина - 12 байт, состоит из трех float-ов (по 4 байта каждый = по 32 бита).
Первое число - X-координата (+X для Maya)
Второе - Y-координата (-Z для Maya)
Третье - Z-координата (+Y для Maya)
 
Сверху