首先,我们需要知道obj文件格式是什么样的,他的内部是如何储存模型的.利用ultra edit打开bunny.obj文件观察可以看到如下数据:
我们猜想,这应该是顶点数据组,拖动滚动条后看到出现了左图的数据.
¨
分析这些数据
,
不难猜想
obj
文件由若干行组成
,
每行开始有一个字母
,
用来标注改行数据所表示的意思
,v
应该是顶点
,g
应该是一个名字
,
观察到
,f
后紧跟着三个整数
,
由
opengl
中的顶点数组得到
,
他应该是三角行的三个顶点
,
后面的三个整数就代表着前端顶点的索引值
.
¨好知道了数据结构,就可以提取分析obj文件啦~(整个过程远比我想象的顺利啊~哈哈)
•
好
,
现在我们就来进行编码工作啦
~
•第一步当然是要定义一个与文件相对应的数据结构啦~我们把它命名为obj3dmodel并有如下头文件结构:
•class obj3dmodel
•{
• struct vertex{
• double x;
• double y;
• double z;
• };
• struct face{
• unsigned int v1,v2,v3;
• };
• std::vector<vertex> vetexes;
• std::vector<face> faces;
•
•
•public:
• void parse(const char* filename);
• void draw();
• obj3dmodel(void);
• ~obj3dmodel(void);
•};
¨这里,我们定义两个结构体来表示顶点和三角形,并采用vector容器来保存数据组.
¨之所以把两个结构体定义在类的内部,一个是不想污染源代码,另一个是暂时还没有想到会在别的什么地方会用到他们.所以暂且把他们藏起来~省着不好管理~
¨我们同时为他定义了parse和draw方法,分别用来从文件中解析数据和利用opengl绘制
•
定义好数据结构后
,
就可以着手
parse
代码的实现啦
~
•void obj3dmodel::parse(const char *filename)
•{
• string s;
• ifstream fin(filename);
• if(!fin)
• return;
• while(fin>>s)
• {
• switch(*s.c_str())
• {
• case 'v':
• {
• vertex v;
• fin>>v.x>>v.y>>v.z;
• this->vetexes.push_back(v);
• }
• break;
• //这里我们暂时不需要名字,直接忽略掉它
• case 'g':
• break;
• case 'f':
• {
• face f;
• fin>>f.v1>>f.v2>>f.v3;
• faces.push_back(f);
• }
• break;
• }
• }
•}
•紧接着,定义draw的方法,比较简单啦~不过注意顶点索引
方式,obj里面是以1为基数的,所以在索引时要将索引值减1.
则会报越界.
•void obj3dmodel::draw()
•{
• glBegin(GL_TRIANGLES);
• for(int i=0;i<faces.size();i++)
• {
• //索引要减去1
• vertex v1= vetexes[faces[i].v1-1];
• vertex v2=vetexes[faces[i].v2-1];
• vertex v3=vetexes[faces[i].v3-1];
• glVertex3f(v1.x,v1.y,v1.z);
• glVertex3f(v2.x,v2.y,v2.z);
• glVertex3f(v3.x,v3.y,v3.z);
• }
• glEnd();
•}
¨新增数据类型,ply文件的导入
¨从网上下载了个3d模型用来做网格参数化,无奈文件是个.ply的文件,无奈没见过.依然用上述方法用ultra edit打开发现文件格式也是很好猜的.依然可以按照文件格式写代码来解析.
¨为使代码便于管理和将来的扩展考虑,我们抽象出一个modelbase类,用来表示任何文件格式的模型:
¨并将parse和draw方法
设置为虚,这样就可以在应
用时统一用modelbase接
口来访问特定的类型了
转载自:http://blog.csdn.net/zamzll/article/details/6530930