OpenGL实现3D模型的交互控制

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

第24卷第10期 计算机应用与软件

Vol 124No .10

2007年10月 Computer App licati ons and Soft w are Oct .2007

O penG L 实现3D 模型的交互控制

孙妮芳 杨志强 陈 诚 何 斌 龚佩曾

(同济大学计算机系 上海 200092)

收稿日期:2006-12-04。孙妮芳,硕士生,主研领域:虚拟现实技术。

摘 要 简述了3DS 文件的结构,以及在OpenG L 中如何读入和显示3DS 文件的模型,并着重讲述了利用OpenG L 编程接口对场

景中的这些模型进行选择、拾取,通过鼠标拖动对这些模型进行交互操作。关键词 OpenG L 选择 拾取 交互操作

CO NTROL THE 3D MOD EL S I NTERACT I VELY I N O PENGL

Sun N ifang Yang Zhiqiang Chen Cheng He B in Gong Peizeng

(D epart m ent of Co m puter ,Tongji U niversity,Shanghai 200092,China )

Abstract The structure of 3DS For mat File is outlined,and the way t o read and show the models of 3DS For mat File in OpenG L is p resen 2ted .It is exp lained in detail how the interactive contr ol of the models with the select mode and the feedback mode is realized .Keywords OpenG L Select Picking I nteractive

0 引 言

虚拟实验是当今教育改革比较热门的话题之一,通常意义上讲的虚拟实验建立在真实实验的基础之上,对实验所使用的元器件、,实验者通过鼠标点击与拖曳、键盘操作,可以像对真实元器件一样对虚拟实验设备进行操作,从而完成整个虚拟实验过程。

交互技术是建立虚拟实验要解决的最基本和最重要的问题,交互不仅可以向用户演示信息,同时允许用户向程序传递一些控制信息,比如用户可以通过键盘、鼠标等外设来控制程序的运行。OpenG L 作为一个三维工具软件包,在三维交互编程等方面提供了比较完善的机制。比如,通过OpenG L 的选择、反馈模式比较容易实现通过鼠标键盘进行交互。

目前,已经有不少论文和书籍比较详细地阐述了在OpenG L 中通过选择、拾取和反馈实现对三维物体的交互操作。但对读入和显示多个3DS 文件的模型的交互操作却介绍得比较少。本文根据这一情况并结合实际,在虚拟装机系统中,对场景中的多个元器件模型的交互操作进行详细介绍。

1 3D S 文件介绍

3DS 文件存储了模型的材质信息和几何信息,材质信息主

要包括材质的名称,材质的纹理贴图所对应的文件名以及材质

的颜色等;几何信息主要包括顶点的数目,每个顶点的坐标,三角面的数目,每个三角面上3个顶点的索引,此三角面是否可见等。

3DS 文件由许多块组成,每个块包括信息类别和下一个块的相对位置。块的信息类别用I D 表示,它描述了该块的数据信息。下一个块的相对位置指出了下一个块相对于该块起始位置

的偏移字节数。在块结构中,始终用前2个字节保存I D 号,接下来的4个字节保存块的长度,块的实际内容则用(块长度)6个字节保存。块的内容又可能包含子块。

在OpenG L 中读入3DS 文件的模型的方法有很多,由于本文的程序是在VC ++环境下开发的,所以采用了编写一个类来加载3DS 文件的方法。这样的类很多书籍和网站都有提供,只需进行简单的修改就可以使用,比如修改模型的位置信息以实现模型的移动,增加模型的旋转经度和纬度信息以实现模型的旋转。

2 O penGL 的交互技术

在虚拟装机系统中,要求与场景本身进行更多的交互操作,这种交互除了菜单和对话框实现外,在很多情况下是用鼠标来进行的。OpenG L 的一大功能就是提供了实现交互技术的机制。OpenG L 的交互技术是通过选择、拾取和反馈操作来实现的。

2.1 选 择

选择允许在窗口内部的某个位置用鼠标进行点击,并确定它所点击的是哪个物体。选择是OpenG L 的一种操作模式,选择模式不会改变帧缓存区的内容,退出选择模式时,OpenG L 返回与视景体相交的图元列表,它列出了位于视景体内或与视景体相交的图元,每个图元产生一个选择命中的记录,对应名称堆栈中的当前内容。

・绘制模式 进入选择模式前,调用函数gl Render M ode (),其原型为:gl Render M ode (G Lenu m mode )。控制应用程序当前所处的模式,即绘图、选择和反馈模式,相应的mode 的取值为G L_RE NDER 、G L _SE LECT 或G L_FEE DBACK 。

208

计算机应用与软件2007年

・创建名称堆栈 名称堆栈的内容可以用来确定用户选择的物体,所以它在选择操作中具有非常重要的作用。首先,用glI nit N a mes()函数初始化名称堆栈,即清除名称堆栈。然后,在发出各模型绘图命令的同时,用glPush Name()函数将物体名称压入堆栈。这名称是整数,OpenG L可以包含64个名称。

操作堆栈的函数有:

glPush Na me()函数,将名称压入堆栈;

glPopNa me()函数,将名称从堆栈中弹出;

gl L oad Na me()函数,用不同的名称替换最顶层堆栈的名称。

・命中记录 命中记录即位于选择物体内或与选择物体相交图元的选中标志。在选择模式下,操纵名称堆栈或调用gl2 Render M ode()函数,OpenG L将命中记录写入选择数组中。对于由多个图元构成的物体,构成物体的各个图元共享同一个名称。

每一个命中记录是由三个部分组成:①当命中记录时,名称堆栈中的名称数目;②自上一个命中记录以来,所有与物体相交的图元顶点的最大和最小窗口坐标Z值;③命中发生时,名称堆栈中的内容,最底层的元素在堆栈的最顶层。

在OpenG L中使用选择机制,必须执行下面几个步骤:

(1)用glSelect B uffer()命令定义用来返回命中记录的数组;

(2)调用gl Render M ode(G L_SE LECT)函数进入选择模式;

(3)用glI nit N a mes()初始化名称堆栈,即清空名称堆栈,然后调用glPush Name()命令将名称压入堆栈;

(4)定义选择使用的选择题,它通常与最初用来绘制场景的视景体不同,因此有可能需要用glPush Matrix()和glPop M atrix ()命令保存并恢复当前视景体的状态;

(5)交替发出图元绘制命令和操纵名称堆栈命令gl L oad2 Na me(),以便每一个图元均被指定一个合适的名字。

(6)终止选择模式,处理返回的选择数据,即命中记录。2.2 拾 取

拾取是选择模式的一种扩展,通常用它来拾取光标附近的物体。为了用拾取操作实现以上功能,进入选择模式后,用指定的拾取矩阵同投影矩阵一起把绘图限制在一个小的视口区域内,通常在光标附近,此时在光标附近的物体就会产生选择命中。使用这种方式,就可以确定哪个物体绘制在光标附近。

拾取操作和选择操作之间的主要区别是:

(1)拾取操作通常由输入装置激发,例如可以用鼠标的点击来激发;

(2)可以使用实用库中的函数gluPick Matrix(),把指定的投影矩阵加到当前矩阵堆栈中。函数原型如下:void gluPick Ma2 trix(Gldouble x,Gldouble y,Gldouble z,Gldouble width,Gldouble high,Glint vie wport[4]);

2.3 反 馈

和选择一样,反馈也是一种渲染模式,它并不会以屏幕像素的形式产生输出。相反,它的信息被写入到反馈缓冲区中,提示场景将如何被渲染。这个信息包括了用窗口坐标表示的经过转换的点数据、根据光照计算产生的颜色数据以及纹理数据。

反馈操作的步骤如下:

(1)调用glFeedback Buffer()函数指定存储反馈信息的数组,该函数中的变量描述了数组的数据类型和写入数组中的数据量。

(2)调用gl Render M ode(G L_FEE DBACK)函数,进入反馈模式。

(3)绘制图元。绘图时,可以多次调用glPassThr ough()函数,为返回的反馈数据插入标记,便于程序分析。

(4)调用gl Render M ode()函数,设置其参数为G L_RE N2 DER,退出反馈模式,gl Render M ode()返回的整数值是反馈数组中存储的数据个数。

(5)分析、处理反馈数组中的数据。

3 VC++编程实现对场景中多个三维模型的交互

关键的程序代码如下:

(1)初始化模型

static t3DModel g_3DModel[2];//定义模型数组CLoad3DS3m_3DS=ne w CLoad3DS;//3D模型定义m_3DS->I nit(″neicun2.3DS″,0);//第一个模型

(2)渲染函数

gl L oadNa me(0);//给第一个三维模型命名m_3DS>show3DS(0,g_3DModel[0].Positi on.x,g_3DModel[0].Po2 siti on.y,g_3DModel[0].Positi on.z,0.6,g_3DModel[0].l ongitude,g_ 3DModel[0].latitude);//显示第一个3DS文件中模型

(3)选择函数

hits=gl Render M ode(G L_RENDER);//收集鼠标单击if(hits<=0)//如果选择发生 return-1;

return select B uf[(hits-1)34+3];

(4)平移函数,修改三维模型沿x,y,z轴平移的量

g_3DModel[hits].Positi on.x+=m_xTranslati on;//沿x轴的平移量g_3DModel[hits].Positi on.y+=m_yTranslati on;//沿y轴的平移量

(5)旋转函数,修改三维模型沿经度和纬度旋转的量

g_3DModel[hits].l ongitude-=theta;//沿经度旋转的量g_3DModel[hits].latitude+=phi;//沿纬度旋转的量

(6)On LButt on Down函数

m_left m ousedown=TRUE;//将鼠标左健按下的状态设为TRUE m_Ldownpos=point;//保存鼠标左健按下的位置

(7)OnRButt on Down函数

m_R ight m ousedown=TRUE;//将鼠标右健按下的状态设为TRUE m_Rdownpos=point;//保存鼠标右健按下的位置

(8)On Mouse Move函数

if(m_left m ousedown)

//如果鼠标左健按下的标志为真,则计算三维模型位置的变化量

{m_xTranslati on=point.x-m_Ldownpos.x;

m_yTranslati on=point.y-m_Ldownpos.y;

hits=DoSelect(m_Ldownpos.x,m_Ldownpos.y);

//收集鼠标左健选中了哪个三维模型if(hits!=-1)

{s witch(hits)

{default:Translati on(hits);//调用平移函数break;}}}

if(m_R ight m ousedown)

//如果鼠标右健按下的标志为真,则计算三维模型旋转的变化量

{theta=point.y-m_Rdownpos.y;

//根据鼠标器的移动改变旋转的纬度phi=point.x-m_Rdownpos.x;

//根据鼠标器的移动改变旋转的经度

相关文档
最新文档