下载

1下载券

加入VIP
  • 专属下载特权
  • 现金文档折扣购买
  • VIP免费专区
  • 千万文档免费下载

上传资料

关闭

关闭

关闭

封号提示

内容

首页 OpenGL实现3DS文件中的模型自由旋转

OpenGL实现3DS文件中的模型自由旋转.pdf

OpenGL实现3DS文件中的模型自由旋转

大玩家时代_109
2011-04-23 0人阅读 举报 0 0 暂无简介

简介:本文档为《OpenGL实现3DS文件中的模型自由旋转pdf》,可适用于人文社科领域

摘要简述如何在OpenGL中读入和显示DS文件中的模型并着重阐述通过鼠标拖动对其进行自由旋转的数学基础和编程实现的方法。关键词OpenGLDS文件格式VC自由旋转现在已经有很多论文和书籍提到在OpenGL中实现读入和显示DS文件中的模型。但是在很多场合仅读入和显示是不够的。我们需要从各个角度观察模型以便更好地理解模型的形态形成更为直观的感性认识。例如在医学髁上骨折诊断中如果把骨折后断骨错位旋转的情况用三维模型模拟出来并仅用鼠标的拖动就能实现从任何角度观看骨折的情况这将对医生做出正确的诊断大有裨益。这也是我们为何考虑实现此项功能的初衷。本文将简要介绍DS文件格式怎样读入和显示模型而重点放在通过鼠标拖动实现模型自由旋转的数学基础和编程实现的方法和经验。DS文件的格式以及读入和显示文件中模型的一些经验DS文件是由许多块(chunk)组成的(大块中镶嵌子块)。由于至今为止没有一个官方的文献说明其格式所以还有很多未知的块。不过这并不影响我们读入DS文件中的模型。因为我们在读入时可以根据自己的需要选择性地读入自己需要的块而忽略掉那些不感兴趣或未知的块。这正是块结构给我们带来的好处。一个块由块信息和块数据组成。块信息又由块的ID(两个字节长的标识如DD)和块的长度(四个字节其实也就是下一个块的偏移字节数)组成。用VC以十六进制方式打开一DS文件可以很清楚的看到其结构。在读入这种块结构(大块中嵌套小块而块的结构固定)的文件时完全可以用递归的方法实现而返回上一级(子块读完返回父块)的条件则是当前已经读入的块的字节数是否等于块的长度。从父块转向读入其子块则可用switch语句实现通过子块的ID判断进入哪个分支。由于在网上有很多现成的这类程序所以完全可是找一个类封装的比较好的程序将其移植到自己的工程中就行了。当然需要做一些小小的改动比如根据自己的需要修改其显示和控制的部分。实现模型自由旋转的数学基础我们用鼠标实现模型的旋转就好像手握一个包含模型的虚拟球一样。按一下鼠标,即在这个虚拟球上确定了一点而拖动鼠标就是移动那个点,这样就实现了对虚拟球的旋转同时达到旋转模型的目的。这个虚拟球的中心位于显示屏的中心这样球的一半则位于显示屏以外(外半球如图所示)。我们用鼠标点击的点将定义为外半球上的点。这种映射关系的数学定义为:其中(xy)是以球心为原点的屏幕坐标R为球的半径。接下来要做的就是在球上给定两个点后(起始点和终点)怎样确定旋转的轴和角度。从图中可以看出:旋转轴是两个鼠标矢量(m和m)所张成的平面的法向量所以可以通过求m和m的叉乘得到即:Axis=mxm(式)而旋转角度就是m和m之间的夹角a因此:a=acos(m*m)(式)在实际应用中我们更习惯取a的两倍值进行旋转。因为这样将更有效地旋转模型。如果用鼠标点击视图的左中边缘然后拖动至视图的右中边缘则可实现模型以y轴为旋转轴的度旋转。从图可以看出:在旋转的过程中两个弧(R和R)的合成所形成的旋转弧等于R的起始点和R的终点形成的旋转弧。即意味着我们定义的虚拟球的旋转运动只决定于起始点和终点。编程实现自由旋转的方法和经验、首先建立一个虚拟球类用面向对象的方法来解决问题能使解决方案有很好的可移植性和可维护性。而VC是功能强大的面向对象编程的工具所以我们使用VC++面向对象程序设计的方案来实现自由旋转功能。虚拟球类的声明如下:classVirtualBall{protected:voidmapToSphere(constPointfT*NewPt,VectorfT*NewVec)constpublic:构造和析构函数VirtualBall(GLfloatNewWidth,GLfloatNewHeight)~VirtualBall(){*不做任何事*}设置边界当窗口大小改变时使虚拟球与窗口大小相适应voidsetBounds(GLfloatNewWidth,GLfloatNewHeight)voidclick(constPointfT*NewPt)鼠标按下映射起始点到虚拟球鼠标拖动第二个鼠标坐标在这里得到更新并映射到虚拟球上计算旋转轴的向量和夹角的信息将它们保存到一个四元数NewRot中(前个元素为坐标信息最后一个元素为关于夹角的信息其实就是两个向量的点乘)voiddrag(constPointfT*NewPt,QuatfT*NewRot)protected:VectorfTStVec保存鼠标点击时的向量(起始点)VectorfTEnVec保存拖动时的向量(终点)GLfloatAdjustWidthsetBounds函数用其来调整窗口GLfloatAdjustHeight}、把鼠标坐标映射为虚拟球上的坐标通过虚拟球的旋转来达到旋转模型的目的关键在于把视图中鼠标点击和拖动的坐标映射为虚拟球上的坐标。为此我们首先简单的把鼠标点击和拖动的范围~width),~height)映射到-~,~-(在映射中我们颠倒了y坐标的符号不然OpenGL中得不到正确的结果)。这样做可以使数学计算变得简单些其映射如下:MousePtX=((MousePtX((Width–)))–)MousePtY=((MousePtY((Height–)))–)其次计算鼠标矢量将鼠标坐标映射到虚拟球上可以根据式的定义完成这一步工作。、些相关变量的设定为实现旋转我们还需要一些变量:MatrixfTTransform最终的变换*矩阵初始化为单位矩阵MatrixfTLastRot上一次的旋转*矩阵需要它是因为旋转的结果是要叠加起来的MatrixfTThisRot这次的旋转*矩阵。PointfTMousePt当前的鼠标坐标boolisClicked=false鼠标按下的标识boolisRClicked=false右键点击的标识boolisDragging=false鼠标拖动的标识其中Transform是我们的最终变换结果LastRot是上一次鼠标拖动得到的旋转结果而ThisRot是当前鼠标拖动的结果。它们都被初始化为单位矩阵。当我们点击鼠标时我们从单位旋转矩阵开始旋转。当拖动鼠标时我们计算从初始点到拖动点的旋转。尽管我们用这信息旋转屏幕上的模型但值得注意的是我们并不是真的旋转虚拟球自身。所以要得到累积的旋转结果我们必须自己想办法这也就是引入LastRot的原因。如果不累积旋转模型就会在我们点击鼠标时突然跑回到原始的状态。例如如果关于X轴旋转度后再旋转度希望得到度的结果但实际上得到的是度。在下一次点击鼠标时又会回到原始的度状态。其他的变量我们要做的就是在适当的时间和地点更新它们。虚拟球需要在窗口大小改变时重新设置它的边界MousePt在鼠标点击和拖动时得到更新isClicked和isRClicked分别标识鼠标的左键和右键是否按下isClicked用来判断是否处于按下和拖动状态我们用isRClicked来重置所有的旋转使其回到单位矩阵状态。、更新旋转矩阵有了以上变量的更新接下来就是根据这些更新实现旋转矩阵的更新:voidCRenderView::OnTimer(UINTnIDEvent){if(mCompleted){mCompleted=falseif(isRClicked)如果点击右键重置旋转{MatrixfSetIdentity(LastRot)把LastRot重置为单位矩阵MatrixfSetIdentity(ThisRot)把ThisRot重置为单位矩阵MatrixfSetRotationFromMatrixf(Transform,ThisRot)}if(!isDragging)没有拖动{if(isClicked)第一次点击{isDragging=true为拖动作准备LastRot=ThisRotVirtualBallclick(MousePt)}}更新起始点为拖动作准备else{if(isClicked)鼠标仍然被按下说明仍处于拖动状态{QuatfTThisQuat一个四元数用来存旋转的信息ArcBalldrag(MousePt,ThisQuat)将四元数转化为旋转矩阵MatrixfSetRotationFromQuatf(ThisRot,ThisQuat)MatrixfMulMatrixf(ThisRot,LastRot)累积旋转结果得到我们最终的旋转结果MatrixfSetRotationFromMatrixf(Transform,ThisRot)}else没有拖动的isDragging=false}mOpenGLDisplayDisplayScene(mpDModel)mCompleted=true}CView::OnTimer(nIDEvent)}其中将四元数转化为旋转矩阵的函数为:staticvoidMatrixfSetRotationFromQuatf(MatrixfT*NewObj,constQuatfT*q){GLfloatn,sGLfloatxs,ys,zsGLfloatwx,wy,wzGLfloatxx,xy,xzGLfloatyy,yz,zzassert(NewObjq)n=(q>sX*q>sX)(q>sY*q>sY)(q>sZ*q>sZ)(q>sW*q>sW)s=(n>f)(fn):fxs=q>sX*sys=q>sY*szs=q>sZ*swx=q>sW*xswy=q>sW*yswz=q>sW*zsxx=q>sX*xsxy=q>sX*ysxz=q>sX*zsyy=q>sY*ysyz=q>sY*zszz=q>sZ*zsNewObj>sXX=f(yyzz)NewObj>sYX=xywzNewObj>sZX=xzwyNewObj>sXY=xywzNewObj>sYY=f(xxzz)NewObj>sZY=yzwxNewObj>sXZ=xzwyNewObj>sYZ=yzwxNewObj>sZZ=f(xxyy)}最后把变换的结果应用于从DS文件中读入的模型:glPushMatrix()glMultMatrixf(TransformM)将旋转的矩阵作用于模型上glBegin(DrawingMode)………此处为画模型的地方即画模型各个面的地方glEnd()glPopMatrix()旋转的结果和问题分析自由旋转的效果如图所示。这种虚拟球旋转DS文件中模型的方法操作简单方便而实用达到预期的目的但这种方法还有值得改进的地方。这个虚拟球的中心是相对固定的(总在窗口的中心)如果模型的中心偏离虚拟球中心太远旋转的效果就不是很好。最简单的解决办法是:用DSMAX导出DS文件前把模型的中心移到坐标原点。这是一个治标的办法但适用且简单。而治本的方法就比较麻烦了可以通过计算模型的中心来确定虚拟球的中心使两个中心重合。如果是多个模型还应考虑实现鼠标捕获模型的功能根据所选模型调节虚拟球的中心。结束语本文着重阐述了实现DS文件中的模型自由旋转的数学基础和编程实现的过程。这项工作是计算机辅助诊断髁上骨折项目的一个重要组成部分。它的实现有利于医生从各个角度观察骨折的模拟情况形成较为直观的感性认识。对其它文件格式中的模型或辅助库中的模型都可以用此办法来实现自由旋转所以具有较强的可移植性和适用价值。

用户评价(0)

关闭

新课改视野下建构高中语文教学实验成果报告(32KB)

抱歉,积分不足下载失败,请稍后再试!

提示

试读已结束,如需要继续阅读或者下载,敬请购买!

文档小程序码

使用微信“扫一扫”扫码寻找文档

1

打开微信

2

扫描小程序码

3

发布寻找信息

4

等待寻找结果

我知道了
评分:

/7

OpenGL实现3DS文件中的模型自由旋转

VIP

在线
客服

免费
邮箱

爱问共享资料服务号

扫描关注领取更多福利