OpenCASCADE View Manipulator
OpenCASCADE View Manipulator
Abstract. When you finish modeling objects in the scene, you must want to use some operations to view the scene objects, such as Pan, Zoom and Rotate the scene. Pan and Zoom is easy to understand, rotate the 3D scene according to 2D point in the viewport is a little complicated. There are many methods to rotate the 3D scene, but the Arcball Controller is intuitive for the user and any viewport can be described. You can rotate your model at will just by using the mouse.
Key Words. OpenCASCADE Camera, View, ArcBall, Rotate
1. Introduction
当 用OpenGL建立了一个模型场景后,就需要有便捷的操作来观察场景中的物体。场景的观察即注重于一个从三维世界转换到二维屏幕的过程。假设场景的观察者 使用一台相机来记录世界的变化,那么相机的移动、角度偏转、焦距变化都会改变底片上显现的内容,也就是观察这个世界的方式,这涉及到三维人机的交互。
三 维用户交互是一种与三维环境本身特性相匹配的交互动作,可使用户在虚拟场景中获得身临其境的直观感受。三维世界的交互技术相当于一种“控制-显示”的映 射,用户设备例如鼠标、键盘等向系统输入控制信息,然后系统向用户输出执行结果。所以首先要对硬件设备的输入信息进行处理,然后就是根据这些信息来改变场 景数据。
三维交互涉及的任务很多,包括三维场景对象的选择和编辑、三维世界中的导航漫游,乃至时下流行的三维交互建模等。本文主要介绍如何通过改变像机参数来对场景进行浏览,如对场景的平移、缩放和旋转操作。
![]()
Figure 1.1 OpenCASCADE Viewer
2.Translate View
场景的移动就是改变观察相机的位置,相对容易理解,在OpenCASCADE的类V3d_View中也是这样实现的,代码如下所示:
// function : Translate
// purpose : Internal
// ==================================================================
void V3d_View::Translate (const Handle(Graphic3d_Camera)& theCamera,
const Standard_Real theDXv,
const Standard_Real theDYv) const
{
const gp_Pnt& aCenter = theCamera->Center();
const gp_Dir& aDir = theCamera->Direction();
const gp_Dir& anUp = theCamera->Up();
gp_Ax3 aCameraCS (aCenter, aDir.Reversed(), aDir ^ anUp);
gp_Vec aCameraPanXv = gp_Vec (aCameraCS.XDirection()) * theDXv;
gp_Vec aCameraPanYv = gp_Vec (aCameraCS.YDirection()) * theDYv;
gp_Vec aCameraPan = aCameraPanXv + aCameraPanYv;
gp_Trsf aPanTrsf;
aPanTrsf.SetTranslation (aCameraPan);
theCamera->Transform (aPanTrsf);
}
由上述代码可知,根据两次鼠标位置计算出需要移动的偏移量来对相机进行移动变换。根据鼠标第一次按下及移动过程中的坐标点来计算偏移量。计算偏移量时,需要注意坐标系的统一,即要么都在视口坐标系,要么都在世界坐标系中。如下代码是将鼠标点变换到世界坐标系中进行移动:
{
gp_Pnt aCurrentPoint = Convert2World(thePoint);
gp_Trsf aTrsf;
aTrsf.SetTranslation(aCurrentPoint, mPreviousPoint);
mCamera->Transform(aTrsf);
}
对相机参数进行修改后,需要更新场景数据。移动场景只涉及到MODELVIEW变换,所以需要刷新模型视图MODELVIEW变换矩阵数据并重绘场景,相关代码如下所示:
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glLoadMatrixf(theArcballController.GetOrientationMatrix());
其中theArcballController的这个函数是调用了Graphic3d_Camera的函数来设置模型视图变换矩阵。经过测试,移动效果还可以,如下图所示为将一个Teapot从屏幕左上角移动到了右下角:
![]()
Figure 2.1 Translate the Scene
3.Zoom View
对
于透视投影而言,靠模型越近,看到模型就越大,因为透视投影的特点就是近大远小。而对平行投影而言,这种规律就不适用了。其实二者都可以统一到通过调整视
口大小来对场景模型进行缩放。同样的模型,当投影到较大的视口中时,模型的投影得到的二维图形也会较大;当投影到较小的视口中时,模型的投影得到的二维图
形也会较小。这样就达到对场景进行缩放的目的了。其中OpenCASCADE中的实现是通过设置Graphic3d_Camera的Scale来实现的,
代码如下图所示:
//function : SetZoom
//purpose :
//===================================================================
void V3d_View::SetZoom(const Standard_Real Coef,const Standard_Boolean Start)
{
V3d_BadValue_Raise_if( Coef <= 0.,"V3d_View::SetZoom, bad coefficient");
if (Start)
{
myCamStartOpEye = myCamera->Eye();
myCamStartOpCenter = myCamera->Center();
}
Standard_Real aViewWidth = myCamera->ViewDimensions().X();
Standard_Real aViewHeight = myCamera->ViewDimensions().Y();
// ensure that zoom will not be too small or too big
Standard_Real coef = Coef;
if (aViewWidth < coef * Precision::Confusion())
{
coef = aViewWidth / Precision::Confusion();
}
else if (aViewWidth > coef * 1e12)
{
coef = aViewWidth / 1e12;
}
if (aViewHeight < coef * Precision::Confusion())
{
coef = aViewHeight / Precision::Confusion();
}
else if (aViewHeight > coef * 1e12)
{
coef = aViewHeight / 1e12;
}
myCamera->SetEye (myCamStartOpEye);
myCamera->SetCenter (myCamStartOpCenter);
myCamera->SetScale (myCamera->Scale() / Coef);
View()->AutoZFit();
ImmediateUpdate();
}
根据鼠标点计算出缩改系数,通过myCamera->SetScale()来达到对场景进行缩放的目的。场景缩放操作涉及到需要更新OpenGL的投影矩阵数据,代码如下所示:
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glLoadMatrixf(theArcballController.GetProjectionMatrix());
![]()
Figure 3.1 Zoom the scene
4.Rotate View
通过鼠标在二维屏幕上来旋转三维的场景有几种方法,如下图所示:
![]()
Figure 4.1 3D Rotation(http://www.cabiatl.com/mricro/obsolete/graphics/3d.html)
方法一是通过Euler Angles来实现,好处是用户比较容易理解Euler角,如yaw, pitch和roll,如下图所示:
![]()
Figure 4.2 Euler Angles: Yaw, Pitch and Roll
缺点就是因为死锁问题(gimbal lock)导致不能指定一些视图,当出现死锁问题时,操作就显得不直观了。
比较直观的方法就是ArcBall方式了,使用这种方法可以以任意方向来查看场景中的模型。有个网页版的实现,可以去体验一下:
http://www.math.tamu.edu/~romwell/arcball_js/index.html
![]()
Figure 4.3 Arcball in Javascript
ArcBall的原理是将二维屏幕上鼠标点转换到球面上,拖动鼠标就是在转动这个球。根据映射到球面的两个点,通过矢量的点乘及叉乘得到旋转角度及旋转轴。通过这种方式可以将二维的鼠标位置映射到三维的场景来实现对场景观察的直观操作。
OpenCASCADE中场景的旋转方式是通过先遍历场景中的模型计算出重心点,再绕三个坐标轴来旋转,代码如下所示:
//function : Rotate
//purpose :
//=============================================================================
void V3d_View::Rotate(const Standard_Real ax, const Standard_Real ay, const Standard_Real az,
const Standard_Real X, const Standard_Real Y, const Standard_Real Z, const Standard_Boolean Start)
{
Standard_Real Ax = ax ;
Standard_Real Ay = ay ;
Standard_Real Az = az ;
if( Ax > 0. ) while ( Ax > DEUXPI ) Ax -= DEUXPI ;
else if( Ax < 0. ) while ( Ax < -DEUXPI ) Ax += DEUXPI ;
if( Ay > 0. ) while ( Ay > DEUXPI ) Ay -= DEUXPI ;
else if( Ay < 0. ) while ( Ay < -DEUXPI ) Ay += DEUXPI ;
if( Az > 0. ) while ( Az > DEUXPI ) Az -= DEUXPI ;
else if( Az < 0. ) while ( Az < -DEUXPI ) Az += DEUXPI ;
if (Start)
{
myGravityReferencePoint.SetCoord (X, Y, Z);
myCamStartOpUp = myCamera->Up();
myCamStartOpEye = myCamera->Eye();
myCamStartOpCenter = myCamera->Center();
}
const Graphic3d_Vertex& aVref = myGravityReferencePoint;
myCamera->SetUp (myCamStartOpUp);
myCamera->SetEye (myCamStartOpEye);
myCamera->SetCenter (myCamStartOpCenter);
// rotate camera around 3 initial axes
gp_Pnt aRCenter (aVref.X(), aVref.Y(), aVref.Z());
gp_Dir aZAxis (myCamera->Direction().Reversed());
gp_Dir aYAxis (myCamera->Up());
gp_Dir aXAxis (aYAxis.Crossed (aZAxis));
gp_Trsf aRot[3], aTrsf;
aRot[0].SetRotation (gp_Ax1 (aRCenter, aYAxis), -Ax);
aRot[1].SetRotation (gp_Ax1 (aRCenter, aXAxis), Ay);
aRot[2].SetRotation (gp_Ax1 (aRCenter, aZAxis), Az);
aTrsf.Multiply (aRot[0]);
aTrsf.Multiply (aRot[1]);
aTrsf.Multiply (aRot[2]);
myCamera->Transform (aTrsf);
View()->AutoZFit();
ImmediateUpdate();
}
5.Conclusion
当实现三维场景的建模后,最激动人心的应该是对场景及场景中模型的控制。通过交互操作使用户方便地观察场景的模型,或直观地编辑场景中的模型。所以交互也是三维软件中的重要功能,且是给用户最直接的感觉的操作。
因
为交互操作涉及到鼠标键盘消息的处理,所以首先要设计好对这些消息的处理方式,在OpenSceneGraph中使用了适配器的方式来实现跨平台的消息处
理,使用户通过继承的方式来实现对消息的处理。这种方式使程序的可扩展性及代码的可读性更好,OpenCASCADE中的消息的处理还是比较直接的,没有
什么封装。
本文主要介绍了如何实现对场景的控制,如移动、缩放及旋转操作,这些功能的实现需要对OpenGL的渲染管线有一定的了解。在
理解了对视图/场景的控制后,为进一步理解对场景中的模型的控制打下基础,如选择Picking,拖拽Drag等操作。最后给出一个基于
OpenCASCADE的类Graphic3d_Camera及GLUT实现的场景变换操作,功能不是很完善,仅供参考。若有好的意见,欢迎反馈。
6. References
1. Brad Smith. ArcBall. http://rainwarrior.ca/dragon/arcball.html
2. WikiBooks. Modern OpenGL Tutorial Arcball.
http://en.wikibooks.org/wiki/OpenGL_Programming/Modern_OpenGL_Tutorial_Arcball
3. sgCore demo code. http://www.cppblog.com/eryar/archive/2013/06/30/201411.html
4. Virtual Trackballs Revisited. http://image.diku.dk/research/trackballs/index.html
5. http://oviliazhang.diandian.com/post/2012-05-19/40027878859
6. 王锐,钱学雷. OpenSceneGraph三维渲染引擎设计与实践. 清华大学出版社. 2009
PDF Version and Source code: OpenCASCADE View Manipulator
OpenCASCADE View Manipulator的更多相关文章
- OpenCASCADE AIS Manipulator
OpenCASCADE AIS Manipulator eryar@163.com Abstract. OpenCASCADE7.1.0 introduces new built-in interac ...
- OpenCASCADE PCurve of Topological Face
OpenCASCADE PCurve of Topological Face eryar@163.com Abstract. OpenCASCADE provides a class BRepBuil ...
- Create views of OpenCASCADE objects in the Debugger
Create views of OpenCASCADE objects in the Debugger eryar@163.com Abstract. The Visual Studio Natvis ...
- OpenCASCADE Hidden Line Removal
OpenCASCADE Hidden Line Removal eryar@163.com Abstract. To provide the precision required in industr ...
- A Simple OpenCASCADE Qt Demo-occQt
A Simple OpenCASCADE Qt Demo-occQt eryar@163.com Abstract. OpenCASCADE have provided the Qt samples ...
- OpenCASCADE Coordinate Transforms
OpenCASCADE Coordinate Transforms eryar@163.com Abstract. The purpose of the OpenGL graphics process ...
- OpenCASCADE Camera
OpenCASCADE Camera eryar@163.com Abstract. OpenCASCADE introduce a new class Graphic3d_Camera for th ...
- OpenCASCADE Conic to BSpline Curves-Circle
OpenCASCADE Conic to BSpline Curves-Circle eryar@163.com Abstract. The conic sections and circles pl ...
- OpenCASCADE Color Scale
OpenCASCADE Color Scale eryar@163.com Abstract. The color scale is a specialized label object that d ...
随机推荐
- css自定义三角形效果
废话不说了,直接上代码 element{ width:0px; height:0px; border-left:10px; border-right:10px; border-bottom:10px; ...
- Git Commands Quick Notes
Fetch This command is to make sure your local repository has the same knowledge of the remote-tracki ...
- [资源分享]yslow 与firebug 修复版本Firefox35【绿色版本下载】
自从火狐也开始做版本帝后,相关查的插件越来越不好使了, 而且火狐集成自己的调试工具,也不是很好使用,Yslow 也坏掉了 找公司写c++修复了下 把yslow和Firebug 打包到一起,而且关闭自动 ...
- NSCache和NSURLCache、网络缓存优化
本文目录 一种缓存优化方案 响应头'Last-Modified'和请求头'If-Modified-Since' 'Keep-Alive'响应头和不离线的URLSession 'Expires'响应头 ...
- nginx 各类网站设置 (laravel , thinkphp , nodejs , https)
基础部分设置 [root@centos ~]# vim /opt/nginx/conf/nginx.conf user www www;worker_processes auto;pid logs/n ...
- PMP备考_第六章_项目时间管理
项目时间管理 前言 项目时间管理是项目管理中最难的一个环节,与个人时间管理类似,团体的效率如果管理不当,是低于个人效率的,为了管理好时间,从预估,执行到反馈均需要严格的分析和处理.如果制定的计划是无法 ...
- 使div下的图片自适应div的大小
div img{ max-width:100%; height:auto; } 这里div 要给固定的宽度 开始这里还想了半天 用网上的方法也不行 问老大 又一句话就给我解决了...老大真男神啊!!! ...
- 爬虫初探(2)之requests
关于请求网络,requests这个库是爬虫经常用到的一个第三方库. import requests url = 'http://www.baidu.com' #这里用get方法用来请求网页,其他还有p ...
- 微信中一些常用的js事件积累
1.网页图片集左右滑动查看图片,如下样例: jjs效果 var pictures = []; angular.forEach(pitctures,function(k,i){ pict ...
- ASP.net之策略模式
设计思路: 用ASP.net设计,调用策略模式.在第一个数和第二个数的文本框中输入数值,单击录题按钮,数值保存在n1,n2文档中,把要做的题都保存完后,单击开始按钮,开始做题,做完单击判断按钮,进行判 ...