读取3ds文件

3ds文件是3D Max的一种二进制存储格式,它始终没被官方公开,但是也基本被大家hack出来了大半。其“格式”总的来说非常简单,这里介绍一个概念:chunk。3ds文件里的数据都是按chunk一块一块隔离的。每个chunk都有两个标记:2个字节大小的chunkId,用来标识这个chunk存的是什么数据。接着是一个4个字节大小的chunkLen,它根据chunkId不同,可能表示该chunk的大小,也可能表示下一个chunk的位置偏移。

-----------------------------

chunk Id       2 Byte

chunk Len   4 Byte

-----------------------------

想要读取3ds文件,chunk Id是比较重要的部分,下面是hack出来的常用Id:

-------------------------------------------------------------------------------------------------------------------------------------

0x4D4D // Main Chunk
├─ 0x3D3D // 3D Editor Chunk
│  ├─ 0x4000 // Object Block
│  │  ├─ 0x4100 // Triangular Mesh
│  │  │  ├─ 0x4110 // Vertices List
│  │  │  ├─ 0x4120 // Faces Description
│  │  │  │  └─ 0x4130 // Faces Material
│  │  │  ├─ 0x4140 // Mapping Coordinates List
│  │  │  │  └─ 0x4150 // Smoothing Group List
│  │  │  └─ 0x4160 // Local Coordinates System
│  │  ├─ 0x4600 // Light
│  │  │  └─ 0x4610 // Spotlight
│  │  └─ 0x4700 // Camera
│  └─ 0xAFFF // Material Block
│     ├─ 0xA000 // Material Name
│     ├─ 0xA010 // Ambient Color
│     ├─ 0xA020 // Diffuse Color
│     ├─ 0xA030 // Specular Color
│     ├─ 0xA200 // Texture Map 1
│     ├─ 0xA230 // Bump Map
│     └─ 0xA220 // Reflection Map
│        │  /* Sub Chunks For Each Map */
│        ├─ 0xA300 // Mapping Filename
│        └─ 0xA351 // Mapping Parameters
└─ 0xB000 // Keyframer Chunk
   ├─ 0xB002 // Mesh Information Block
   ├─ 0xB007 // Spot Light Information Block
   └─ 0xB008 // Frames (Start and End)
      ├─ 0xB010 // Object Name
      ├─ 0xB013 // Object Pivot Point
      ├─ 0xB020 // Position Track
      ├─ 0xB021 // Rotation Track
      ├─ 0xB022 // Scale Track
      └─ 0xB030 // Hierarchy Position
------------------------------------------------------------------------------------------------------------
一般来说,一个chunk可能还包含子chunk,比如0x4100表示Mesh的chunk里就包含了0x4110,0x4120等chunk,同时,0x4100这个chunk的长度标识,是把这些子chunk的长度也计算在内的。一般来说,我们读取3ds文件,只要解析主要chunk,遇到不识别的chunk,跳过即可。因为3ds里的数据,大多数并不是程序员需要的。我们只要顶点和uv这些就够了。 
下面是读取3ds文件的源代码:
IModel.h
View Code
 1 #ifndef IModel_h__
2 #define IModel_h__
3 /********************************************************************
4 created: 2012/03/20
5 created: 20:3:2012 20:08
6 author: Baesky
7
8 purpose: provide an interface for loading model from various format.
9 *********************************************************************/
10
11 class IModelLoader
12 {
13 public:
14 virtual bool Load(const char* fileName) = 0; //load model file
15 virtual unsigned short* GetIB() = 0; //got index buffer
16 virtual float* GetVB() = 0; //got vertex buffer
17 virtual short GetVertexNum() = 0; //got vertex num
18 virtual unsigned short GetPolygonNum() = 0;
19 };
20
21 #endif // IModel_h__
Model3ds.h
View Code
 1 #pragma once
2 #include "imodel.h"
3
4 #define MAINCHUNK_3DS 0x4D4D
5 #define MASHDATA_3DS 0x3D3D
6 #define OBJNAME_3DS 0x4000
7 #define MESH_DATA_3DS 0x4100
8 #define VERTEX_DATA_3DS 0x4110
9 #define INDEX_DATA_3DS 0x4120
10 #define TEXMAP_DATA_3DS 0x4140
11
12 struct SVertex3DS
13 {
14 union
15 {
16 float v[3];
17 struct
18 {
19 float X;
20 float Y;
21 float Z;
22 };
23 };
24 };
25
26 struct SIndex3DS
27 {
28 union
29 {
30 unsigned short i[3];
31 struct
32 {
33 unsigned short p1;
34 unsigned short p2;
35 unsigned short p3;
36 };
37 };
38 };
39
40 class CModel3ds :
41 public IModelLoader
42 {
43 public:
44 CModel3ds(void);
45 virtual ~CModel3ds(void);
46
47 //interface
48 bool Load(const char* fileName);
49 unsigned short* GetIB();
50 float* GetVB();
51 inline short GetVertexNum(){return m_VertexNum;}
52 inline unsigned short GetPolygonNum(){return m_PolygonNum;}
53 private:
54 SIndex3DS* m_pIBbuff;
55 SVertex3DS* m_pVBbuff;
56 unsigned short m_VertexNum;
57 unsigned short m_PolygonNum;
58 };
Model3ds.cpp
View Code
 1 #include "Model3ds.h"
2 #include <iosfwd>
3 #include <fstream>
4 using namespace std;
5
6 CModel3ds::CModel3ds(void):m_pIBbuff(0),m_pVBbuff(0),m_VertexNum(0)
7 {
8
9 }
10
11
12 CModel3ds::~CModel3ds(void)
13 {
14 if(m_pIBbuff)
15 delete m_pIBbuff;
16 if(m_pVBbuff)
17 delete m_pVBbuff;
18 }
19
20 bool CModel3ds::Load(const char* fileName )
21 {
22 ifstream f;
23 f.open(fileName, ios::in|ios::binary);
24
25
26 short chunk_id = 0;
27 unsigned int chunk_len = 0;
28 while(!f.eof())
29 {
30 f.read((char*)&chunk_id, 2);
31 f.read((char*)&chunk_len,4);
32 switch(chunk_id)
33 {
34 case MAINCHUNK_3DS://find out main chunk
35 break;
36 case MASHDATA_3DS: //find out mesh obj
37 break;
38 case OBJNAME_3DS:
39 {
40 int i=0;
41 char c;
42 do
43 {
44 f.read(&c,1);
45 i++;
46 }while(c != '\0' && i<20);
47 }
48
49 break;
50 case MESH_DATA_3DS:
51 break;
52 case VERTEX_DATA_3DS: //find out the vertex data
53 f.read((char*)&m_VertexNum,2);
54 m_pVBbuff = new SVertex3DS[m_VertexNum];
55 for(int i = 0; i<m_VertexNum; ++i)
56 {
57 f.read((char*)&(m_pVBbuff[i].X),sizeof(float));
58 f.read((char*)&(m_pVBbuff[i].Y),sizeof(float));
59 f.read((char*)&(m_pVBbuff[i].Z),sizeof(float));
60 }
61 break;
62 case INDEX_DATA_3DS:
63 f.read((char*)&m_PolygonNum, 2);
64 if(m_PolygonNum <= 0) return false;
65 m_pIBbuff = new SIndex3DS[m_PolygonNum];
66 for(int i = 0; i<m_PolygonNum; ++i)
67 {
68 f.read((char*)&m_pIBbuff[i].p1, 2);
69 f.read((char*)&m_pIBbuff[i].p2, 2);
70 f.read((char*)&m_pIBbuff[i].p3, 2);
71 f.seekg(2, ios_base::cur);
72 }
73 break;
74 case TEXMAP_DATA_3DS:
75 break;
76 default:
77 f.seekg(chunk_len - 6, ios_base::cur);
78 }
79 }
80 f.close();
81 return true;
82 }
83
84 unsigned short* CModel3ds::GetIB()
85 {
86 return (unsigned short*)m_pIBbuff;
87 }
88
89 float* CModel3ds::GetVB()
90 {
91 return (float*)m_pVBbuff;
92 }
需要注意的是,3ds文件没normal chunk,所以法向量需要我们自己来计算。

下面来读取下Cube.3ds(可从RenderMonkey附带例子中找到该文件)试试:



posted on 2012-03-24 20:27  Meta.Grfx  阅读(10567)  评论(0编辑  收藏  举报

导航