项目实践与用OpenGL实现OBJ模型文件的读入

来源:互联网 发布:25 知乎 编辑:程序博客网 时间:2024/06/14 15:46

 

 

我们的项目做的是把人的照片转为三维头像。这其中需要将人脸轮廓提取出来,根据照片得到人头模型,把人的照片作成贴图,贴在模型上。

我们小组原本打算用SFS得到人脸模型,但深入研究了以后发现SFS是个很高端的领域,难度过大,于是我们决定先做出一个普通人脸模型,然后根据照片调整这个人脸模型。

由于我主要负责人脸模型的建立,在这里我主要讲讲如何用OpenGL将模型读入。

首先介绍一下OpenGL

OpenGL全称Open Graphics Library,既开放的图形程序接口,它是在行业领域中最为广泛接纳的2D/3D图形API,虽然Direct3D也是十分优秀的图形API,但它只用于Windows系统。而OpenGL不仅用于Windows,还可以用于,Unix/Linux等其它系统,它甚至在大型计算机、各种专业计算机(如:医疗用显示设备)上都有应用。并且OpenGL的基本命令都做到了与硬件无关,甚至是平台无关。

更重要的是它和C语言密切结合,对于学过C语言的人来讲容易上手。如果你想用计算机作图但不知道从何下手,如果你只会C语言,建议你学OpenGL

这里的OBJ文件,并不是我们编程的时候出现的,用于编译应用程序的文件。这里的OBJ文件是指Alias|Wavefront公司为它的一套基于工作站的3D建模和动画软件"Advanced Visualizer"开发的一种标准3D模型文件格式。它很适合用于3D软件模型之间的互导,用3D MAX就可以导出OBJ文件。

OBJ文件是一种文本文件格式,可以直接用写字板打开。打开后你会发现它非常简洁整齐,下面是一个示例的OBJ文件内部。

关于它的具体文件结构,各位可以网上查找更详细的内容,在这里我们只关注顶点数据。v指几何体顶点,vt指贴图坐标点,vn指顶点法线,f是索引号,有左斜线(/)表示:f 顶点索引/贴图坐标点索引/法线索引。索引号指的其实是点的顺序。假设有4个点,点1,点2,点3,点4f 1 2 3 4 的连接顺序是点1234,而f 1 3 2 4 的连接顺序就是点1324

然后我们就可以写程序,读入OBJ文件了。先用fopen读入文件,然后我们让程序一行一行地读文件。可以看到,文件开始有两行对我们没用的信息: 读到这两行以后,不操作。

接着是 这行连接了一个材质文件.mtl,但由于我在OpenGL文件中已经指定了贴图,这行也不操做。

继续,读到了定义物体的地方。

上面示例的OBJ文件只有一个名为skin_hi的物体:

每个这样的结构都定义了一个物体。我们在程序中也应该定义一个物体数据类型。

这是我定义的数据类型,OBJECTS体现整个OBJ文件共有多少物体,同时能指向各个物体。OBJECT指一个物体,含有v的数量和f的数量,和存储的v,vn,vt,f的指针,通过观察发现vnvtv的数量一样,因此不另外指出。

F数据类型用来存储 f v/vt/vn。每个索引对应的点、贴图坐标、发现分别存储在x[i][0]x[i][1]x[i][2],当s=4时,用x[0]~x[3]存储,s=3时,用x[0]~x[2]存储。

VETTEX,VNORMAL,VT用的都是float x,y,z,但vt由于对应的是平面图形,只有xy

好了,接下去只要遇到点就读在点的数组里,遇到法线就读在法线的数组里,以此类推。注意内存空间的申请,就可以成功地读文件了。

在写这个读OBJ文件的程序时,感触最深的就是各种数据,必须时刻保持清晰的头脑否则很容易就混了。其实我这个数据结构还可以进一步优化。毕竟各种数据结构相嵌套在使用的时候很不方便。在写的过程中,我发现,它的索引值(即f后面的数字)是不断累加的,并不是每个物体都从1开始,也就是说,可以只定义OBJECT,而不定义OBJECTS,因为我们并不关心一个文件中究竟有多少物体,我们只要把所有物体画出来就可以了。而不断累加的f值使得能把所有点都放在一个数组中,而不用像我一样,把每个物体的点分开为一个数组存放。

好了,把OBJ文件读进去了,接下去我们该把它绘制出来了。

首先,在初始化OpenGL环境时,加入

在绘制函数中加入

 

glBegin()glEnd()OpenGL绘制的部分,glBegin()的参数体现了绘制的图形类型,glVertex3f()是绘制点的函数。下面一段代码体现了OpenGL绘制三角形的方法。

glBegin(GL_TRIANGLES);        

   glVertex3f( 0.0f, 1.0f, 0.0f);    

   glVertex3f(-1.0f,-1.0f, 0.0f);    

   glVertex3f( 1.0f,-1.0f, 0.0f);     

glEnd();

下面贴出我们项目的范例图片。

原始

旋转

眼睛缩小 眼睛放大

眼睛缩小与眼睛放大,是对眼睛对应的坐标点进行缩放变换。虽然效果有些生硬,但体现的是我们有能力对个别坐标点进行变化。我们项目目前遇到的问题是如何把照片上的二维点转变为空间中的三维点,或者说,不知道怎么把照片与模型联系在一起。

通过这个项目,我们学到了很多,就我个人而言,激发了我对OpenGL的兴趣,同时对编程也有了进一步理解。而且一整个大工程下来,对项目的制作、团队的配合有了更深的体会。 

原创粉丝点击