编程小技巧:如何加载3DS文件
将你的3D引擎运作起来,假如你仅看到屏幕上只有两或三个立方体或球体。那么你需要增加一些时间去适应更复杂的模型。下面的代码会列出如何加载3D Studio R3或更高版本的.3DS文件。请注意代码仅仅加载顶点数据,面数据及材质,而不会理睬其它的信息(例如照相机,光源,关键帧数据等),因此我的目的是仅仅装载网格。
So, you have your 3D engine (written in D3DIM or OpenGL) up and running, but you only have 2 or 3 cubes or spheres on the screen. Time to add some more complex models. The code below listed can be used to load a 3D Studio R3 or higher .3DS files. The code loads only the vertex data, face data and materials. It ignores all other information (like camera, light, keyframe data etc), since for my purposes, I only need the mesh loaded.
正如你所看到,代码写得很差,但我不在乎。因为它正在不顾一切的往我的D3DIM 3D引擎加载网格文件。代码部分对于一般的C/C++程序员而言是通俗易懂的。并且我增加了一些注释,希望它可以帮助你学习。代码读取.3DS文件并创建了材质表及网格对象表。材质表包含了网格所使用的材质信息。网格包含了材质表涉及到的材质(即名字)。
If you think the code is written badly, I don't care! because it does the job and it was my desperate attempt to load some mesh into my D3DIM 3D Engine. But the code is (I hope!) simple and self explanatory for an average C/C++ programmer (or for that matter any programmer who can read C/C++ code). I have added some comments, see if it helps you. The code reads the .3ds file and creates a material list and mesh object list. The material list contains all the materials used by the mesh. The mesh contains references to the material in the material list (i.e the name).
与面数据一起出现的标识显示面的顺序以方便计算面法线。但是好象只有前面三位有用(我的看法)。代码中没有标识因为我用不着。如果你找到了标识的用处请告诉我。忽略标识在有些文件中会改变面法线,使面看不见。但在其它文件中这种操作运行良好。
The flag present along with face data gives the order of the faces for calculating face normals. Only the first (I think!) 3 bits are used. The code ignores the flag because I don't need it, but if you figure out the use of that flag, please let me know. Ignoring the flag in some files inverts the face normals for some faces, so it becomes invisible. But other files it works okay.
顺便说一句,变换矩阵包含本地轴及本地原点信息。
BTW the transformation matrix contains the local axis and local origin (if it is of any use 2 you).
假如你对代码有任何问题,或是想知道如何装载照相机/光源及其它的信息...你可用英文信与我联系。注意:你需要适当的修改源代码以更好的适应你的引擎。
If you have any questions about the code, or info about how to load camera/lights and other things.... you can contact me at digicrush_ii@rediff.com..Note: You'll need to modify the code in order to make it work with your engine. I had to cut this out of a project that I am working on, so it might or might not compile right away... If anyone else out there is developing a 3-D engine and wants to share code/ideas, feel free to e-mail me at digicrush_ii@rediff.com. (FYI I'm using Visual C++ 6.0 with DX7.0)
// Copyright (c) 2000. Aanand Narayanan.P.P
// For questions email digicrush_ii@rediff.com
// Reads a .3ds file and create a linked list of objects
#include
#define D3DOVERLOADS
#include
typedef struct _map_list
{
char filename[256];
// Mapping filename (Texture)
float u;
// U scale
float v;
// V scale
float uoff;
// U Offset
float voff;
// V Offset
float rot;
// Rotation angle
_map_list *next;
}map_list;
typedef struct _mat_list
{
char name[200];
// Material name
DWORD ambient;
// Ambient color (RGBA)
DWORD diffuse;
// Diffuse color (RGBA)
DWORD specular;
// Specular color (RGBA)
_map_list *htex, *ttex;
// Texture maps (presently only 1 is used. diffused map)
_mat_list *next;
}mat_list;
typedef struct _face_mat
{
char name[200];
// Material Name
WORD ne;
// No. of entries
WORD *faces;
// Faces assigned to this material
_face_mat *next;
}face_mat;
typedef struct _mesh_object
{
char name[200];
// Object name
float *vlst;
// Vertex list
WORD *flst;
// Face list
WORD nv;
// No. of vertices
WORD nf;
// No. of faces
WORD mnv;
// No. of vertices having mapping coords.
float *mc;
// Mapping coords. as U,V pairs (actual texture coordinates)
float lmat[4][4];
// Local transformation matrix
_mesh_object *next;
// Pointer to the next object
face_mat *fhead, *ftail;
}mesh_object;
char temp_name [100];
float trans_mat [4][4];
// translation matrix for objects
FILE *bin3ds;
mesh_object *head=NULL, *tail=NULL;
mat_list *mathead=NULL, *mattail=NULL;
map_list *maphead=NULL, *maptail=NULL;
void ReadObject();
unsigned char ReadChar (void)
{
return (fgetc (bin3ds));
}
unsigned int ReadInt (void)
{
unsigned int temp = ReadChar();
return ( temp | (ReadChar ()
// I really don't know Y I'm do'n this, too lazy to change
}
unsigned long ReadLong (void)
{
unsigned long temp1,temp2;
temp1=ReadInt ();
temp2=ReadInt ();
return (temp1 | (temp2
// same as above
}
void read_mat(DWORD len)
{
unsigned long count=ftell(bin3ds) + (len - 6);
WORD id;
DWORD llen;
int done = 0;
BOOL is_ambient = FALSE;
BOOL is_diffuse = FALSE;
BOOL is_specular = FALSE;
// Allocate a new material
if(mathead == NULL)
{
mathead = new mat_list;
mattail = mathead;
}
else
{
mattail-next = new mat_list;
mattail = mattail-next;
}
mattail-next = NULL;
mattail-htex = NULL;
while(!done)
{
id = ReadInt();
if(feof(bin3ds))
// OOPS! EOF
{
done = 1;
break;
}
llen = ReadLong();
switch(id)
{
case 0xA000:
{
int i=0;
char ch;
mattail-next = NULL;
// Read material name
while((ch = fgetc(bin3ds)) != 0)
{
mattail-name[i] = ch;
i++;
}
mattail-name[i] = '\0';
}break;
case 0xA010:
{
// Hey! AMBIENT
is_diffuse = FALSE;
is_specular = FALSE;
is_ambient = TRUE;
mattail-ambient = 0;
}break;
case 0xA020:
{
// Hey! DIFFUSE
is_diffuse = TRUE;
is_specular = FALSE;
is_ambient = FALSE;
mattail-diffuse = 0;
}break;
case 0xA030:
{
// OH! SPECULAR
is_diffuse = FALSE;
is_specular = TRUE;
is_ambient = FALSE;
mattail-specular = 0;
}break;
case 0xA200:
{
// Texture
if(mattail-htex == NULL)
{
mattail-htex = new _map_list;
mattail-htex-next = NULL;
mattail-ttex = mattail-htex;
}
else
{
mattail-ttex-next = new _map_list;
mattail-ttex = mattail-ttex-next;
mattail-ttex-next = NULL;
}
mattail-ttex-u = mattail-ttex-v = mattail-ttex-uoff = mattail-ttex-voff = 0.0;
mattail-ttex-rot = 0.0;
}break;
case 0xA300:
{
// Texture name (filename with out path)
char ch;
int i=0;
while((ch = fgetc(bin3ds)) != 0)
{
mattail-ttex-filename[i] = ch;
i++;