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

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

1 3DS文件介绍
3DS文件存储了模型的材质信息和几何信息,材质信息主要包括材质的名称,材质的纹理贴图所对应的文件名以及材质的颜色等;几何信息主要包括顶点的数目,每个顶点的坐标,三角面的数目,每个三角面上3个顶点的索引,此三角面是否可见等。

3DS文件由许多块组成,每个块包括信息类别和下一个块的相对位置。

块的信息类别用ID表示,它描述了该块的数据信息。

下一个块的相对位置指出了下一个块相对于该块起始位置的偏移字节数。

在块结构中,始终用前2个字节保存D号,接下来的4个字节保存块的长度,块的实际内容则用(块长度)6个字节保存。

块的内容又可能包含子块。

在OpenGL中读入3DS文件的模型的方法有很多,由于本文的程序是在VC + +环境下开发的,所以采用了编写一个类来加载3DS文件的方法。

这样的类很多书籍和网站都有提供,只需进行简单的修改就可以使用,比如修改模型的位置信息以实现模型的移动,增加模型的旋转经度和纬度信息以实现模型的旋转。

1 OpenGL的交互技术
在虚拟装机系统中,要求与场景本身进行更多的交互操作,这种交互除了菜单和对话框实现外,在很多情况下是用鼠标来进行的。

OperGL的一大功能就是提供了实现交互技术的机制。

OperGL的交互技术是通过选择、拾取和反馈操作来实现的。

2 1选择
选择允许在窗口内部的某个位置用鼠标进行点击,并确定它所点击的是哪个物体。

选择是OpenGL的一种操作模式,选择模式不会改变帧缓存区的内容,退出选择模式时,OperGL返回与视景体相交的图元列表,它列出了位于视景体内或与视景体相交的图元,每个图元产生一个选择命中的记录,对应名称堆栈中的当前内容。

绘制模式进入选择模式前,调用函数gR endeM ode (),其原型为:gRendeMode(GLmum mode)。

控制应用程序当前所处的模式,即绘图、选择和反馈模式,相应的mode的取值为 GL—RENDER、GL—SELECT
或 GL—FEEDBACK。

•创建名称堆栈名称堆栈的内容可以用来确定用户选择的物体,所以它在选择操作中具有非常重要的作用。

首先,用 gUnitNaneS()函数初始化名称堆栈,即清除名称堆栈。

然后,在发出各模型绘图命令的同时,用gPuthName()函数将物体名称压入堆栈。

这名称是整数,OpenGL可以包含64个名称。

操作堆栈的函数有:
gIPushName()函数,将名称压入堆栈;
gPcpNam e()函数,将名称从堆栈中弹出;
gLoadName()函数,用不同的名称替换最顶层堆栈的名称。

/淀义模型数组 //3D模型定义 /第一个模型
/給第一个三维模型命名
•命中记录命中记录即位于选择物体内或与选择物体相交图元的选中标志。

在选择模式下,操纵名称堆栈或调用gt RendeMode()函数,OpenGL将命中记录写入选择数组中。

对于由多个图元构成的物体,构成物体的各个图元共享同一个名称。

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

在OpenGL中使用选择机制,必须执行下面几个步骤:
(1) 用gLSeledBuffcr()命令定义用来返回命中记录的数组;
(2) 调用gRemieM(xle(GL_SELECT)函数进入选择模式;
(3) 用gUniNameS()初始化名称堆栈,即清空名称堆栈,然后调用gIPushName()命令将名称压入堆栈;
(4) 定义选择使用的选择题,它通常与最初用来绘制场景的视景体不同,因此有可能需要用gPushMatrk()和gIPopiatrk ()命令保存并恢复当前视景体的状态;
(5) 交替发出图元绘制命令和操纵名称堆栈命令gLoad- Name(),以便每一个图元均被指定一个合适的名字。

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

2 2拾取
拾取是选择模式的一种扩展,通常用它来拾取光标附近的物体。

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

使用这种方式,就可以确定哪个物体绘制在光标附近。

拾取操作和选择操作之间的主要区别是:
(1) 三维模型位置的变化量
拾取操作通常由输入装置激发,例如可以用鼠标的点击来激发;
(2) 维模型
可以使用实用库中的函数gluPickMatrk(),把指定的投影矩阵加到当前矩阵堆栈中。

函数原型如下:voiigluPickMa- trix( G Ll^^juble x, G Lioub Le y, G Idoub Le % G LioubLe w ii ill, G LioubLe h gh G Lint viewport[ 4]);
2 3反馈
和选择一样,反馈也是一种渲染模式,它并不会以屏幕像素的形式产生输出。

相反,它的信息被写入到反馈缓冲区中,提示场景将如何被渲染。

这个信息包括了用窗口坐标表示的经过转换的点数据、根据光照计算产生的颜色数据以及纹理数据。

反馈操作的步骤如下:
(1)调用gFe«ibackBuffer()函数指定存储反馈信息的数组,该函数中的变量描述了数组的数据类型和写入数组中的数据量。

( 2) 调用g lRende rM ode( GL_FEEDBACK)函数, 进入反馈模式。

( 3) 绘制图元。

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

( 4) 调用g lRende rM ode ( ) 函数, 设置其参数为GL _REN DER, 退出反馈模式, g lRenderM ode( ) 返回的整数值是反馈数组中存储的数据个数。

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

3 VC + +编程实现对场景中多个三维模型的交互
关键的程序代码如下:
(1) 初始化模型
static t3DM oieL g_3DMoieL 2|;
CLoai3DS* m _3D S= new CLoai3DS; m _3D S - > Jh it( neicun! 3DS , 0);
(2) 渲染函数
gLLoaiN am e( 0);
m_3DS> sliow3DS( 0, g_3DMoieL| 0 |. Position x, g_3DMoieL| 0 |. Po- siirai y g_3DM oieL| 0 |. Position z 0 亡 g_3DM oieL| 0 |.g_ 3DM oieL| 0 |. Latiiuie); //显示第一个3DS文件中模型
(3) 选择函数
his= gLRenieM oie(GL_RENDER); /收集鼠标单击
if( his< = 0) / /如果选择发生
return 一 1; return seLectBuf ( his- 1)* 4+ 3|;
(4) 平移函数,修改三维模型沿x y z轴平移的量
g_3DMoieL hits|. Positirai x+ = m_XT ransLatirai; //沿 x轴的平移量 g_3DMoieL hits|. PosiiiR y+ = m_yT rnnshtjbii; //沿 y轴的平移量
(5) 旋转函数,修改三維模型沿经度和纬度旋转的量 g_3DMoieL hits|. Longituae- = theta; //沿经度旋转的量 g_3DMoieL hits|. htiude+ = phi //沿玮度旋转的量
( 6) OnLButtonDown函数
m _leftm ousedown = TRUE; / /将鼠标左健按下的状态设为TRUE
m _Ldow npos= poin t; / /保存鼠标
( 7) OnRButtonDow n函数
m _Righ tm ousedow n= TRUE; / /将鼠标右健按下的状态设为TRUE
m _Rdownpos= poin t; / /保存鼠标右健按下的位置
( 8) OnM ouseM ove函数
if( m _leftm ou sedown )
/ /如果鼠标左健按下的标志为真, 则计算三维模型位置的变化量
{m _xTranslation= poin t. x- m _Ldow npos. x;
m _yT rans lation= point. y- m _Ldow npos. y;
h its= DoS elect( m _Ldow npos. x, m _Ldownpos. y);
/ /收集鼠标左健选中了哪个三维模型
if( h its! = - 1)
{ sw itch( h its)
{ d efau lt: T ran slat ion ( h its); / /调用平移函数
break; } } }
if (m _R ightm ousedow n)
/ /如果鼠标右健按下的标志为真, 则计算三维模型旋转的变化量
{ th eta = poin t. y- m _Rdow npos. y;
/ /根据鼠标器的移动改变旋转的纬度
ph i = poin t. x- m _Rdow npos. x;
/ /根据鼠标器的移动改变旋转的经度
h its= DoSelect( m _Rdow npos. x, m _Rdownpos. y);
/ /收集鼠标右健选中了哪个三维模型
if( h its! = - 1)
{ sw itch( h its)
{ defau lt: Rotate( h its) ; / /调用旋转函数
break; } } }
( 9) OnLButtonUp函数
m _ leftm ou sedow n= FALSE; / /将鼠标左健按下的状态设为FALSE m _Ldow npos= point; / /保存鼠标左健的位置
( 10) OnRButtonUp函数
m _R igh tm ou sedown = FALSE; / /将鼠标右健按下的状态设为FALSE m _Rdow npos= poin t; / /保存鼠标右健的位置
( 11) 在OnD raw 函数中调用渲染场景的函数
Rend erScene( ) ; / /渲染场景
4 实验结果
用编写的类实现读入和显示3DS文件中的电脑元器件模型, 如图1所示。

用开发的程序可以任意选择场景中多个模型中的某个模型, 进行平移和旋转, 如图2所示。

相关文档
最新文档