基于OpenGL的3DS文件解析及视点移动和三维选择的实现

2011-01-24 12:24常洪强李国超
电子设计工程 2011年20期
关键词:视点三维重建纹理

常洪强,刘 爽,李国超,吴 娜

(大连民族学院 计算机学院,辽宁 大连 116600)

随着硬件的不断进步促使虚拟技术的高速发展,其中尤以三维技术为之最,大至三维影院,小至3D裸眼手机都是虚拟三维技术的成果。在本文之前已有不少论文和著作讨论了3DS文件的解析,但很多情况下用户需要的不仅仅是一个静态的场景,还需要从各个不同的方向、视点观察,或者是希望依靠简单的鼠标点击来选取其中的模型获取信息,从而形成更为直观的感官上的认识。文中以解析3DS文件为入口点,对视点移动和三维选取做出分析说明,并讨论其实现的方法和经验。

1 3DS文件的解析

3DS文件记录了由AutoDesk公司的3DSMax[1]导出的3D模型的数据,但由于版权保护等原因,用户无法从Autodesk公司以及任何与AutoDesk公司有关的公司获得有关二进制3DS文件的性质和内容的任何支持,但是这并不影响3DS文件的解析,通过已知的数据结构同样可以获得所需的数据,这也是3DS文件数据结构的优势之一,下面是本应用解析3DS的方法。

1.1 3DS文件数据结构

以二进制打开任何一个3DS文件,可以发现其内容都是以4D4D开头,如图1所示。因此可以通过判断文件起始的两个字节是否为0x4D4D来判断文件是否为3DS格式。

3DS文件内部是以“块”为单位的。所谓“块”就是指相同类型数据信息的集合,但是并不是所有的块都是三维重建所需要的,因此必须对需要的块进行挑选,对不清楚其作用或者无用的块直接跳过即可,而决定是否挑选一个块是根据判断该块的块头信息。3DS文件中所有的块都是以一个且仅为一个块头为起始[2]的,块头之后即为块的内容,所谓“块头”是指由两个字节保存的块的ID及4个字节保存的块的长度信息构成的,块的ID标识该块的身份,块的长度标识该块内容的长度。如表1所示。

表1 3DS文件的一个块的结构Tab.1 A block structure of 3DS file

图1 3DS文件的十六进制数据Fig.1 Hex data of 3DS file

因此只需要知道对应块的ID即可获取该块的数据信息,而3DS文件中所有的块以树形结构结合在一起,就是说大块中包含小块,最后所有大块归结到一起,就是“祖块”,其块ID即为0x4D4D,即表1所示。也就是说,3DS文件内容本身就是一个块,其chunk_id为0x4D4D,其chunk_length即为文件的长度。

1.2 3DS文件的解析

三维重建所需的块均是组块的一级子块或多级子块,每个块所包含的信息不同,所以其内部的数据结构也并不相同。一级子块中的主编辑块中包含了三维重建过程中必须的数据信息[3],如对象信息、材质信息等等。如图2所示。

图2 3 DS文件树形结构Fig.2 3DS file tree

对象块中包含三维重建所需的最重要的点块和面块以及UV纹理坐标块。

点块中顺序存放着三维场景中所有的点,保存了每个点对应三维场景的XYZ坐标,存储为两个字节的浮点型,也就是说从开始的每连续的3个浮点数对应1个点,每个点的ID号就是该点在点块中被读取时的顺序号,这样,在之后的面块中就可以根据其中保存的索引号找到点块中对应ID号的点。在此需要注意的是,OpenGL的空间坐标系是右手坐标系,而3DS文件的坐标系是左手坐标系,因此在读取时要对其进行适当的转化,将读取的坐标值的Y坐标与Z坐标对调,并将对调之后的Z坐标翻转。

在3DS中,每个面是由3个点构成的,所以在面块中,存放着每个面对应3个点在点块中的索引,根据点的索引即可搜索到点的三维坐标,另外,面块中也存放着该面块所包含所有面的对应的材质名称,根据材质名称到材质库中查找并将查找到的材质加入包含该面块的对象的材质数组中。

三维场景最醒目的当属其中逼真的三维环境,其主要由现实世界的图片嵌合在三维物体上实现的,而图片与三维物体嵌合的位置则是由UV纹理坐标块决定的。UV纹理坐标是二维坐标,每个坐标有2个浮点数构成,与之前读取的点块中每个点依次对应,所以纹理坐标的数量与点块中点数完全相同。之所以会依次对应是因为纹理坐标块中每个纹理坐标都是针对点块中对应的点,图片可以看做是一个二维物体,如果将二维物体映射到三维物体上而没有其他参照物的话,则必须对这个二维物体进行旋转、移动,但如果事先可以确定某一特定的面,则不必进行其余操作,节省大量资源,也就是说应用纹理坐标之前首先由点块中对应的3个点确定一个平面,然后再由3个纹理坐标确定该面所贴的贴图的位置,同时,对象也由这些点确定并绘制的,这样一张二维图片即可完美的和一个三维物体嵌合。需要注意的是,一张图片可能不仅仅对应一个面,可能会映射几个在同一平面或不同平面上的面,这是由各个面对应的材质块中指定的纹理贴图来决定的。

这里有个事实,材质块永远先于点块读取,点块永远先于UV纹理坐标块读取,UV纹理坐标块永远先于面块读取。3DS文件中并不是所有的材质都存放在同一材质块中,材质块不等同于材质库,所有的材质块组成了材质库,而每个对象只是选择材质库中一个或多个材质,映射到该对象所包含的各个面中。每个材质块中包含了特点面所需的所有材质的信息,包括材质环境光成分、散射光成分、对应贴图名等等。对象块中每个对象通过索引映射材质库中的材质,从而绘制出五彩缤纷的三维世界[4]。至此,三维重建所需的必要数据信息块就可以获取了。

2 视点移动

所谓视点移动,就是在一个虚拟的场景中,场景的画面根据外部设备的输入产生有规律的变化,变化的前提是场景画面是可刷新的,不管场景是被动刷新还是主动刷新。既然视点移动是根据外部设备的输入产生变化的[6],那么作者就以“鼠标移动控制视角看向的方向,‘W’‘A’‘S’‘D’控制视点前后左右移动”为例来进行说明。

2.1 分析

通常来说,当按下‘W’或者‘S’时,视点会在视角看向的方向上前移或后退,当按下‘A’或者‘D’时,视点会在视角看向的方向的垂直面上向左或右移动,当鼠标移动时视角会根据鼠标的移动来判断方向。因此,对一个视点进行移动并判断看向的方向,关键是判断视点移动方向上的向量以及鼠标的移动方向上的向量

图3 视点移动示意图Fig.3 Viewpoint movement diagram

2.2 实现

设以下变量为已知:

球体半径:R 值:1

视点移动一次的长度:S 值:1

视点起始位置:dtstart 值:(a,b,c)

视点起始目标位置:dtend 值:(a1,b1,c1)

圆切面:CW

终点:mtend

新的视点目标位置:dtend′

首先根据起止点求出视点方向

当按下“W”或“S”时,视点在dt方向上移动,且移动距离为 S,则

从而得到了新的目标点位置dtend。

综上所述,根据以上计算方法可以很轻松的得到视点的移动位置和视点目标位置,接着在应用程序里刷新场景即可获得最新的三维画面,如图4所示。

3 三维选取

图4 视点移动位置及目标位置的变化Fig.4 Viewpoint movement location and the changes of destination position

在多数的交互式三维应用中都允许用户使用外部设备选取屏幕上显示的三维实体,但相对于平面选取,三维选取要困难的多,因为屏幕上显示的图像只是三维实体的二维表现,并且用户点击屏幕产生的只是一个二维坐标,需要对此二维坐标进行旋转、平移、投影等一系列操作形成新的三维坐标,然后以视点为起点,经过该三维坐标形成一条射线,最后在三维场景中与此射线相交的物体即为鼠标选中物体。那么进行三维选取的关键就是射线的分析和计算。

3.1 分析

OpenGL生成虚拟场景类似于通过一个放置在三维世界中的摄像机来观察当前场景中的对象。通过使用诸如gluPerspective()这样的OpenGL函数,用户可以设置这个摄像机所能看到的视野的大小范围。这个视野的边界所围成的几何体是一个标准的平截头体(Frustum),可以看做是金字塔状的几何体削去金字塔的上半部分后形成的一个台状物,如果还原成金字塔状,就得到了通常所说的视锥(View Frustum)这个视锥的锥顶就是视点(View Point)也就是摄像机所在的位置。平截头体,视锥以及视点之间的关系,如图5所示。

图5 二维坐标的三维选取映射Fig.5 The three-dimensional selection mapping of two-dimensional coordinates

如图5所示,点P和点P’分别在近裁剪面A-B-C-D和远裁剪面A1-B1-C1-D1上。用户点击屏幕上的点P,反映到视锥中,就是选中了所有的从点P到点P’的点。举个形象的例子,这就像是用户射击打靶,如果飞出去的子弹近乎笔直地飞出,从射击的地点直至击中目标靶子,在这条直线的轨迹上任何物体都将被一穿而过。对应这里的情况,用户单击鼠标获得屏幕上的某一点,即是指定了从视点指向屏幕深处的某一方向,也就确定了屏幕上某条从O点出发的射线(在图中即为OP),文中称其为拣选射线。因此,从窗口的XY坐标,用户仅仅只能获得一条出发自O点的拣选射线,并不能得到用户想要的点在这条射线上的确切位置。这时候窗口坐标的Z值就能派上用场了。通过Z值,来指定用户想要的点在射线上的位置。假如用户点击了屏幕上的点(100,100)得到了这条射线OP,那么传入值的1.0f就表示近裁剪面上的P点,而值0.0f则对应远裁剪面上的P’点。这样,用户通过引入一个窗口坐标的Z值,就能指定视锥内任意点的三维坐标。

3.2 实现

要使用OpenGL选择反馈机制[6]需要切换渲染模式,操作命名堆栈,计算拣选矩阵,检查选中记录,其主要步骤是:

1)分配一个数组作为存放被选择实体信息的缓冲区,使用glSelectBuffer()函数选择这个数组;

2)glRenderMode()函数,参数设为 G L_SE L E C T ,使程序进入选择模式(selection mode);

3)glInitNames()和 glPushName()函数,初始化名字堆栈(name stack);

4)gluPickMatrix()和 gluPerspective()函数, 进行视图变换,在此之前需要调用glPushMatrix()函数保存变换状态;

5)绘制场景中的各个实体;

6)gluPopMatrix()恢复原来的变换状态,g l R e n d e r Mo d e()函数参数设为GL_RENDER,使程序进入正常渲染模式,同时得到被选中的实体数量;

7)如果被选中的实体数量多于1个,则对其进行排序,保证距离屏幕最近的实体被选择。这些步骤中关键的在于第2步和第5步。

OpenGL的选择模式是一种特殊的光栅化模式,在这种模式下,并不会在屏幕上画出任何东西,而是将各个实体的信息存入缓冲区,在这种模式中,颜色、深度、模板和累积缓存的内容不受影响。由于选择模式的这个特点,系统可以把各个实体的绘制单独编写成一个函数,这个函数既可以在普通模式下绘制屏幕上看得见的实体,又可以在选择模式下绘制实体。

4 结束语

追求虚拟现实是未来计算机发展的必然趋势,三维重建首当其冲。文中阐述了3DS文件的解析流程及视点移动和三维选取的实现说明,针对传统三维建模的不足,即虽然模型建设进度较快,但缺少人机交互能力,利用3DS文件数据结合OpenGL进行三维重建模式,在充分利用三维建模软件的快速建模能力的同时,也展现了OpenGL的强大的人机交互能力,达到了较好的三维重建效果。

[1]刘欣乐,仇建明.3dsMax建筑场景效果图表现[M].北京:北京理工大学出版社,2009.

[2]和平鸽工作室.OpenGL高级编程与可视化系统开发(系统可视篇)[M].北京:中国水利水电出版社,2003.

[3]和平鸽工作室.OpenGL高级编程与可视化系统开发(高级编程篇)[M].北京:中国水利水电出版社,2003.

[4]李国超,刘爽,张延超,等.VC环境下基于OpenGL与3DS的三维场景重建[J].电脑知识与技术, 2010, 26(10):10131-10133,10144.LI Guo-chao,LIU Shuang,ZHANG Yan-chao,et al.Three dimensional modeling based on OpenGL and 3DS[J].Computer Knowledge and Technology, 2010, 26 (10):10131-10133,10144.

[5]Donald H,Baker MP.Computer graphics with OpenGL[M].北京:电子工业出版社,2005.

[6]Shreiner D,The dhronos OpenGL ARB working group.OpenGL编程指南[M].北京:机械工业出版社,2010.

猜你喜欢
视点三维重建纹理
基于BM3D的复杂纹理区域图像去噪
基于Mimics的CT三维重建应用分析
使用纹理叠加添加艺术画特效
TEXTURE ON TEXTURE质地上的纹理
基于关系图的无人机影像三维重建
三维重建结合3D打印技术在腔镜甲状腺手术中的临床应用
消除凹凸纹理有妙招!
视点
多排螺旋CT三维重建在颌面部美容中的应用
让你每天一元钱,物超所值——《今日视点—2014精萃》序