读取3DS文件

读取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

 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

 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

 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,所以法向量需要我们自己来计算。

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
一个完善的读取3DS文件例子 作者:野草我想做个室内渲染程序,要加载3ds室内模型,我本来不想深入研究3ds文件格式的,但是我在网上找了好几个读取3ds文件的例子,不是只能显示网格,就是只能帖一张图,要么只能读版本低的文件. 反正是找不着一个比较完善的类.比如 www.gametutorials.com 上的读取3ds文件的例子就有问题,一读我用3ds max5.0 生成的3ds文件就会非法操作,而且一个物体只能帖一张图; http://www.tsrevolution.com 上的C3DS类的例子只能显示网格; http://www.spacesimulator.net上能读取3ds max 5.0的文件,但也只能帖一张图.看来不研究3ds文件格式是不行的了.上面提到的程序多多少少都有3ds文件格式的说明,但都是E文的了.我在这里也不想详细说3ds文件格式,我只是想,用这个类的人不用知道它的格式就可以很好的用它.如果你真要研究,上面的网站你可以参考一下.首先说明,这个类只是把上面提到的几个例子融合在一起,并作了些改进而已.不要说我抄袭别人的代码. J 只是为了方便大家.我想最好的说教莫过于例子了,于是我就在这里提供一下例子,你可以根据你的需要修改这个例子.在我的应用里模型全都有帖图.在这个例子里我假设你的模型用的都是帖图而没使用颜色,如果你的模型没有用帖图,那模型的颜色应该不是你想要的.如果你想要加载颜色又不想研究3ds文件格式,来信告诉我,我再完善它.加载3ds模型只是游戏开发的一小步,还有很多事情要做.如果你只是就像我例子里那样加载一个比较大的模型并且也像我的例子里那样显示的话,你会发现速度奇慢无比 L 加快显示速度就是你要做的第二件事.比如用Portal技术,我的另一个程序里已经实现了.如果你想要看一下效果,可以到我的网站下载Demo : http://3dbrothers.kom.cn 本地下载:Load3DSDemo.rar
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值