WorldWind源码剖析系列:相机类CameraBase

相机基类CameraBase

  PluginSDK中的相机类CameraBase是三维计算机图形学中的概念。观察者在三维场景中漫游时,通过眼睛看到的场景和相机拍摄过程非常一致。实际上,Direct3D和OpenGL都是先通过对现实世界中的场景先进行世界变换,再通过设置观察矩阵以在场景中安置一个虚拟相机,构建一个视景体来裁剪场景的可见区域,然后在通过投影变换(平行投影或透视投影),获取三维场景的“像”,最后再通过视口变换,将场景的“像”光栅化输出到二维显示屏幕上。如下图所示。

WorldWind源码剖析系列:相机类CameraBase

在三维地形系统中,通常定义一个虚拟相机来实现对三维场景的漫游等功能。可以通过操纵虚拟相机来实现在虚拟场景中切换和漫游。这种方式实质上是通过不断改变虚拟相机的相关参数(如位置和朝向等),然后通过这些参数重新构造世界矩阵、观察矩阵或投影矩阵来完成场景漫游的。

  最后,可以用三句话来概括这些变换的作用:世界变换矩阵决定模型的位置,观察变换矩阵决定模型在观察者(相机)眼中的位置,投影变换矩阵决定模型在屏幕空间中的位置。

根据相机的运动特性,可以将相机简单地分为状态型相机、运动型相机和惯性保持型相机。

(1)      状态型相机也叫静态相机,它适合实现稳定静态的空间表达,很多三维应用就是通过状态型相机来实现静态场景的表达的,用户可以通过交互调整相机的位置、方向来实现场景的切换。状态型相机不需要定义相机对象,不适合用于场景漫游表达需要。目前常在部分动态场景中绑定一些功能型状态相机来捕捉场景的变换,如设在机车上的监视相机用于表达从车上观看车内的景观,动的其实不是相机,而是机车模型。

(2)      运动型相机主要针对漫游实现的快捷交互响应实现,通常需要通过相机类对象来完成封装,使它更适合于快速计算视点、视向变化所引起的模型矩阵转换,并通过一定的机制来提供良好的场景交互接口。

(3)      惯性保持型相机则是在运动型相机的基础上,充分利用力学物体运动的知识,使得场景的变化更贴近人的交互感觉,如给地球一个选转力拖动释放后,它不会立即停止旋转,而是会慢慢地停下来,这种相机就像处理物体惯性一样有一个状态保持过程。

无论哪一种类型相机,其实对计算机图形处理运算来说,最终需要两个转换矩阵来完成对模型的取景变化:观察变换矩阵和投影变换矩阵。这里将世界变换矩阵从相机空间中独立出来时希望明确相机空间的操作其实与场景模型表达不同,世界坐标变换针对的是模型,时由模型自身与场景空间组织决定的,而不是由相机空间决定的。相机空间的处理归根结底可以说时围绕着观察变换矩阵和投影变换矩阵这两个变换矩阵进行的。

相机类的类图如下。由相机基类CameraBase派生出世界相机类WorldCamera,再派生出运动相机类MomentumCamera。

WorldWind源码剖析系列:相机类CameraBase

其中,基类CameraBase主要成员有:地形高程、(所观察的)星球半径(单位为米)、相机所在经度角度_longitude、纬度角度_latitude、相机的朝向角度_heading、_tilt倾斜角度、_bank横滚角度、_distance眼睛到目标的距离、_altitude相机到海平面的高度、四元数m_Orientation、视景体对象_viewFrustum、从星球设置参数获取的相机视场角,相机的_position向量。

同时设置相机的最小倾斜角度为0度,最大倾斜角度为85度。最小高度为10度,最大高度为无穷大。

m_ProjectionMatrix投影变换矩阵、m_ViewMatrix观察变换矩阵、m_WorldMatrix世界变换矩阵。viewRange可视范围角度,trueViewRange真实的可视范围角度,viewPort视口窗口结构体。lastStepZoomTickCount最后一步缩放计数器(与Environment.TickCount结合),cameraUpVector相机的向上向量,初始化默认为Point3d(0,0,1)。ReferenceCenter相机的参考中心,初始化默认为Point3d(0,0,0),lastResetTime最后的重置时间,DoubleTapDelay双Tap延迟。

m_absoluteViewMatrix、m_absoluteWorldMatrix、m_absoluteProjectionMatrix三个绝对矩阵不清楚与上面的三个相应矩阵有什么区别?还为它们定义了只读的属性AbsoluteViewMatrix、AbsoluteWorldMatrix、AbsoluteProjectionMatrix。

属性Altitude和TargetAltitude分别表示高出海平面的高度和经过移动后目标高出海平面的高度。

属性AltitudeAboveTerrain表示高出地表物体高程的高度。属性TerrainElevation用于设置或获取地表物体高程的高度。

属性Distance和TargetDistance分别表示到目标位置的距离和经过移动后到目标位置的距离。

ComputeDistance( double altitude, Angle tilt )用给定的相机高度和相机倾斜角计算距离。

方法ComputeAltitude( double distance, Angle tilt )的计算示意图如下所示。

WorldWind源码剖析系列:相机类CameraBase

定位与视野控制剖面视图

方法ComputeTilt(_altitude, _distance) 的计算示意图如上所示。

ComputeAbsoluteMatrices()方法里面的矩阵我知道意义,但不太理解其运算的含义。为啥要那样运算?

虚方法Update(Device device)用相机新的世界矩阵、观察矩阵、投影矩阵更新当前场景,同时也更新了视景体的参数、可视范围角度,真实的可视范围角度和World.Settings中关于相机的参数。

虚方法Reset() 用于重置相机的参数。调用了虚方法SetPosition()。

虚方法PointGoto(double lat, double lon)设置相机位置。调用了虚方法SetPosition()。

虚方法SetPosition(double lat, double lon, double heading, double _altitude, double tilt, double bank)真正的被设计用来设置设置相机位置,有三种重载形式。

虚方法virtual void PickingRayIntersection(int screenX, int screenY,out Angle latitude,out Angle longitude)用给定的屏幕像素坐标计算对应位置的经度角度和纬度角度。用构造的向量Vector3 v1 = newVector3(screenX, screenY, Viewport. MinZ)和Vector3 v2 = newVector3(screenX, screenY, Viewport. MinZ)调用了Vector3. Unproject(object viewport, Matrix projection, Matrix view, Matrix world)方法拟向将一个向量从屏幕空间投影到目标空间。实现反算射线上一点的空间坐标,这样反算出来的位置即为空间坐标下的E点或F点,然后再根据模型求交反算出真正需要的地球表面点M。这里针对全球地形表达模型,假设相对于地球半径地面高程可以忽略,认为要求取的这一点来源于标准地球表面,可通过视线与球面的交计算出来。然后再用一元二次方程的判别式(Why?)决定经度角度和纬度角度的取值情况。如果判别式>0,则再通过方法MathEngine.CartesianToSphericalD()计算出点对象Point3d p1 = new Point3d(v1.X, v1.Y, v1.Z)和Point3d p2 = new Point3d(v2.X, v2.Y, v2.Z)所对应的球面坐标,最后调用Angle.FromRadians返回以度表示的经度角度和纬度角度。这实际上是计算机图形学中光线跟踪反算空间模型位置的经典问题,其目的就是通过对屏幕上的鼠标响应到空间场景中进行交互拾取选择。由于投影变换实现的是从三维到二维的非线性映射,所以在进行光线跟踪时信息维度的丢失使得准确的逆向过程比较困难。屏幕交互视点的大地空间反算求解如下图所示。这里可以参考韩元利编著的《DirectX 11高级图形开发技术实战》一书和《光线跟踪技术的原理与实现》和《3D未来争夺战——光线追踪算法浅析》两篇论文。

WorldWind源码剖析系列:相机类CameraBase

WorldWind源码剖析系列:相机类CameraBase

WorldWind源码剖析系列:相机类CameraBase

虚方法ComputeProjectionMatrix(Viewport viewport)计算投影矩阵,用于将三维相机或观察空间坐标转换为二维的屏幕空间坐标。

虚方法RotationYawPitchRoll(Angle yaw, Angle pitch, Angle roll)使相机按照给定的航偏角yaw、倾斜角pitch和横滚角roll旋转,实际上是给相机的经度角度_longitude、纬度角度_latitude、相机的朝向角度_heading重新赋值。如下图所示。

WorldWind源码剖析系列:相机类CameraBase

虚方法ZoomStepped通过键盘或鼠标缩放场景。

虚方法Zoom(float percent)在目标距离方向上按指定的百分比缩放。

虚方法Pan(Angle lat, Angle lon)按指定的经、纬度偏移漫游场景。

方法Vector3 Project( Vector3 point ) 用于将世界空间中的三维点转换为二维的屏幕坐标。

静态方法static Angle[] getViewBoundingBox()以度为单位计算可见的外包围盒。

好了,绕了一大圈,总结一下CameraBase类的功能:CameraBase类是管理与虚拟相机位置相关信息的类,内容如下:

a)         设置或获取经纬度、高度、视角角度、倾斜度等位置/视角变量;

b)        各种变化矩阵和计算矩阵的函数,计算的参数由a)中的变量提供;

c)         漫游相关的函数,包括平移、放大、缩小、移位(PointGoto)等功能,而所作的操作也是依据用户操作改变a)中的变量;

d)        刷新/重置的函数;

e)         其他功能。

当需要改变位置时,调用的是WorldWind对象的drawArgs的WorldCamera参数,传入参数即可。在程序窗体Paint函数刷新界面是会自动进行视角变换及相关必须的计算。

世界相机类WorldCamera

  世界相机类WorldCamera 继承自 CameraBase,重载了父类的很多虚方法。

运动相机MomentumCamera

  运动相机MomentumCamera继承自WorldCamera,重载了父类的很多虚方法。

定位与视野控制

  本部分内容请参照《World Wind Java三维地理信息系统开发技术指南》一书。其中不正确或不明确部分已经做了相应的注释。

WorldWind源码剖析系列:相机类CameraBase

WorldWind源码剖析系列:相机类CameraBase

上一篇:SmartCode.ETL 这不是先有鸡还是蛋的问题!


下一篇:HIS系统患者实体OO设计的一点思考