Розшифрування формату 3ds
Тобто перетворення з бінарного формату в текстовий, з виділенням основної інформації. Завантаження тривимірної моделі з текстового файлу не являє собою великої проблеми.
Файли 3ds складаються з кусків (chuncks). Кожен кусок містить іформацію про конкретний об’єкт. Кусок може мати підкуски. Всі вони містяться всередині одного головного.
Тривимірні моделі являють собою сітку трикутників (triangle mesh). Кожен трикутник – це номери трьох вершин (vertices), нумерація починається з нуля. А вершина – це три координати, і дві текстурні координати.
Мій конвертер базується на статті Damiano Vitulli. В ній ви можете прочитати про формат 3ds детальніше. Також є стаття на gamedev.ru.
Формат
Результатом роботи програми є текстовий файл, який містить список об’єктів файлу.
Кожен об’єкт починається рядком "N 1"
, що значить, що далі буде одна назва об’єкта. Назва об’єкта – просто рядок символів, яким об’єкт ідентифікували в 3d редакторі.
Далі ідуть блоки, які задають геометрію об’єкта. Початок кожного з них позначається рядком з буквою і числом. Число показує кількість рядків блоку.
- Буква
V
(Vertices) позначає список вершин. В цьому блоці кожен рядок містить три дійсні числа – координати вершини. - Буква
M
(Mapping) позначає список текстурних координат. В цьому блоці кожен рядок містить два дійсні числа – текстурні координати вершини. Кількість текстурних кординат мала б бути такою ж як і кількість вершин. - Буква
P
(Polygons) позначає список граней. В цьому блоці кожен рядок містить три цілі числа – номери вершин трикутника. Грані в 3ds бувають тільки трикутні.
Оце і все. Добре було б ще мати нормалі до кожної вершини, але на жаль, їх прийдеться обчислювати вручну. Або взагалі не обчислювати. Як воно працює з анімаціями, я не знаю. Скоріш за все також не працює. Але це все таки краще, ніж набридлий усім кубик, що обертається.
Що з цим робити далі, читайте в наступній статті. Там також є гарні картинки :).
Код
/* Program for converting 3ds into text files Copyleft: Bunyk T. www.bunyk.wordpress.com */ #include <stdio.h> #include <stdlib.h> #include <sys/stat.h> long filelength(int f) { struct stat buf; fstat(f, &buf); return(buf.st_size); } void Convert3DS (char *p_filename,char *resfilename) { int i; //Index variable FILE *l_file; //File pointer FILE *rfile; // resultfile float tmp; // temporary variables, for loading from files unsigned short tmpi; unsigned short l_chunk_id; //Chunk identifier unsigned int l_chunk_lenght; //Chunk lenght unsigned char l_char; //Char variable unsigned short l_qty; //Number of elements in each chunk unsigned short l_face_flags; //Flag that stores some face information if ((l_file=fopen (p_filename, "rb"))== NULL) return 0; //Open the file if ((rfile=fopen (resfilename, "wt"))== NULL) return 0; //Open the result file while (ftell (l_file) < filelength (fileno (l_file))) //Loop to scan the whole file //while(!EOF) { //getchar(); //Insert this command for debug (to wait for keypress for each chuck reading) fread (&l_chunk_id, 2, 1, l_file); //Read the chunk header fread (&l_chunk_lenght, 4, 1, l_file); //Read the lenght of the chunk switch (l_chunk_id) { //----------------- MAIN3DS ----------------- // Description: Main chunk, contains all the other chunks // Chunk ID: 4d4d // Chunk Lenght: 0 + sub chunks //------------------------------------------- case 0x4d4d: break; //----------------- EDIT3DS ----------------- // Description: 3D Editor chunk, objects layout info // Chunk ID: 3d3d (hex) // Chunk Lenght: 0 + sub chunks //------------------------------------------- case 0x3d3d: break; //--------------- EDIT_OBJECT --------------- // Description: Object block, info for each object // Chunk ID: 4000 (hex) // Chunk Lenght: len(object name) + sub chunks //------------------------------------------- case 0x4000: fprintf(rfile,"N 1\n"); i=0; do { fread (&l_char, 1, 1, l_file); if(l_char) fprintf(rfile,"%c",l_char); i++; }while(l_char != '' && i<20); fprintf(rfile,"\n"); break; //--------------- OBJ_TRIMESH --------------- // Description: Triangular mesh, contains chunks for 3d mesh info // Chunk ID: 4100 (hex) // Chunk Lenght: 0 + sub chunks //------------------------------------------- case 0x4100: break; //--------------- TRI_VERTEXL --------------- // Description: Vertices list // Chunk ID: 4110 (hex) // Chunk Lenght: 1 x unsigned short (number of vertices) // + 3 x float (vertex coordinates) x (number of vertices) // + sub chunks //------------------------------------------- case 0x4110: fread (&l_qty, sizeof (unsigned short), 1, l_file); fprintf(rfile,"V %d\n",l_qty); for (i=0; i<l_qty; i++) { fread (&tmp, sizeof(float), 1, l_file); fprintf(rfile,"%f",tmp); fread (&tmp, sizeof(float), 1, l_file); fprintf(rfile," %f",tmp); fread (&tmp, sizeof(float), 1, l_file); fprintf(rfile," %f\n",tmp); } break; //--------------- TRI_FACEL1 ---------------- // Description: Polygons (faces) list // Chunk ID: 4120 (hex) // Chunk Lenght: 1 x unsigned short (number of polygons) // + 3 x unsigned short (polygon points) x (number of polygons) // + sub chunks //------------------------------------------- case 0x4120: fread (&l_qty, sizeof (unsigned short), 1, l_file); //p_object->polygons_qty = l_qty; fprintf(rfile,"P %d\n",l_qty); for (i=0; i<l_qty; i++) { fread (&tmpi, sizeof (unsigned short), 1, l_file); fprintf(rfile,"%d",tmpi); fread (&tmpi, sizeof (unsigned short), 1, l_file); fprintf(rfile," %d",tmpi); fread (&tmpi, sizeof (unsigned short), 1, l_file); fprintf(rfile," %d\n",tmpi); fread (&l_face_flags, sizeof (unsigned short), 1, l_file); } break; //------------- TRI_MAPPINGCOORS ------------ // Description: Vertices list // Chunk ID: 4140 (hex) // Chunk Lenght: 1 x unsigned short (number of mapping points) // + 2 x float (mapping coordinates) x (number of mapping points) // + sub chunks //------------------------------------------- case 0x4140: fread (&l_qty, sizeof (unsigned short), 1, l_file); fprintf(rfile,"M %d\n",l_qty); for (i=0; i<l_qty; i++) { fread (&tmp, sizeof (float), 1, l_file); fprintf(rfile,"%f",tmp); fread (&tmp, sizeof (float), 1, l_file); fprintf(rfile," %f\n",tmp); } break; //----------- Skip unknow chunks ------------ //We need to skip all the chunks that currently we don't use //We use the chunk lenght information to set the file pointer //to the same level next chunk //------------------------------------------- default: fseek(l_file, l_chunk_lenght-6, SEEK_CUR); } } fclose (l_file); // Closes the file stream fclose (rfile); } int main() { char fn[50]; char nfn[50]; printf("Input 3ds file name: "); scanf("%s",fn); printf("Input result file name:"); scanf("%s",nfn); Convert3DS(fn,nfn); return 0; }
Чорт, як жаль, що я не читав твій блог тоді, я також колись таким страждав:
http://www.delphisources.ru/pages/sources/graph/2008-year/3ds-viewer.html
dmytrish
24 Вересня, 2012 at 23:22