Cesium中的相机—HeadingPitchRoll
在Cesium中,常常使用HeadingPitchRoll三个角度来定义相机坐标系相对某基准坐标系的方位。
在详细阐述这个概念之前,先阐述在航空飞行中常用的yaw/pitch/roll。
偏航(yaw)/俯仰(pitch)/滚动(roll)
在航空中,常用yaw,pitch,roll这三个词来表示飞机的俯仰、偏航、和滚动。为了避免混淆,这里暂时不用坐标系x,y,z轴来表示具体的旋转轴,而只是用描述性的语言。
首先看这三个词的翻译:
- yaw:(火箭、飞机、宇宙飞船等)偏航
yaw是偏航的意思,如果要改变航向,飞机必定是绕着重力方向为轴; - pitch: 倾斜;投掷;搭帐篷;坠落
pitch有倾斜、坠落的意思。飞机在坠落时,必定会一头栽下去,以翅膀所在的直线为轴。常翻译为俯仰。 - roll: 卷;滚动,转动;辗
roll的意思是翻滚,中文中飞机的翻滚是什么,就是绕着机身所在的那个轴。
再来看看简单的动画来描述yaw/pitch/roll
- 偏航(yaw),即机头朝左右摇摆
- 俯仰(pitch),机头上下摇摆
- 滚转(roll),机身绕中轴线旋转
使用单独一副图来描述飞机的yaw/pitch/roll.
Cesium中的Heading/Pitch/Roll的定义
注意,在上面描述飞机三个方向的旋转时,我们并没有将yaw/pitch/roll与具体的x,y,z轴关联,也没有指定yaw/pitch/roll的前后顺序,这主要是因为并没有一个具体的标准。
重点来了:
在Cesium中,Heading就是yaw,即偏航的意思。则相机的Heading/pitch/roll与飞机类似:
- Heading=yaw,表示相机绕Up轴旋转,Up轴为+Z轴,且定义绕-Z轴旋转为正。
- Pitch,表示相机绕Right轴旋转,Right轴为-Y轴,且定义绕-Y轴旋转为正。
- Roll,表示相机绕Direction轴(视线方向)旋转,Direction轴为+X轴,且绕+X轴旋转为正。
相机的三个旋转方向见下图示意,同时给出了Cesium中相机的Up/Right/Direction三个轴与X/Y/Z轴的关系。
下面给出Heading/Pitch/Roll的旋转顺序:
初始时刻,相机以坐标系o−xyzo-xyzo−xyz为参考基准,相机坐标系o−XYZo-XYZo−XYZ与之重合。
- 绕z轴旋转角度ψ\psiψ;
- 接着绕新的y轴(下图中的N(y’))旋转角度θ\thetaθ;
- 最后绕着新的x轴(下图中的X轴)旋转角度ϕ\phiϕ。
即相机坐标系经过三次基本的欧拉旋转,旋转到最终的坐标系o−XYZo-XYZo−XYZ(下图红色),欧拉转序为321(ZYX),旋转的角度遵循右手定则。
注意,在Cesium中,常使用对象headingPitchRoll来表示相机的三次旋转角度,使用heading属性表示绕z轴旋转的角度(绕-z轴为正);使用pitch表示绕y轴旋转的角度(绕-y轴为正);使用roll表示绕x轴旋转角度(绕+x轴为正);旋转顺序仍为321(ZYX)。
因此,对比ψθϕ\psi\theta\phiψθϕ,有以下关系:
ψ=−headingθ=−pitchϕ=roll\psi = -heading \\ \theta = -pitch \\ \phi = roll ψ=−headingθ=−pitchϕ=roll
旋转矩阵的表示
因此,以后再考虑HeadingPitchRoll旋转时,可正常按照321转序,欧拉角为ψ、θ、ϕ\psi、 \theta 、\phiψ、θ、ϕ,只要注意前两个角度需要添加负号。
相机坐标系经过三次基本旋转(ZYX)后,以[X,Y,Z]T\begin{bmatrix} X,Y,Z\end{bmatrix}^{T}[X,Y,Z]T表示点P在相机坐标系o−XYZo-XYZo−XYZ中的坐标分量(始终不变),[x,y,z]T\begin{bmatrix} x,y,z\end{bmatrix}^{T}[x,y,z]T表示点P随相机旋转后在原坐标系o−xyzo-xyzo−xyz中的坐标分量,则有:
[xyz]=M(ψ,θ,ϕ)[XYZ]=Mz(ψ)⋅My(θ)⋅Mx(ϕ)⋅[XYZ]=[cosψ−sinψ0sinψcosψ0001][cosθ0sinθ010−sinθ0cosθ][1000cosθ−sinθ0sinθcosθ][XYZ]=[cosθcosψ−cosϕsinψ+sinϕsinθcosψsinϕsinψ+cosϕsinθcosψcosθsinψcosϕcosψ+sinϕsinθsinψ−sinϕcosψ+cosϕsinθsinψ−sinθsinϕcosθcosϕcosθ][XYZ](1)\begin{bmatrix} {x}\\{y} \\{z} \end{bmatrix}=M(\psi,\theta,\phi) \begin{bmatrix} X \\Y \\Z \end{bmatrix} = M_z(\psi)\cdot M_y(\theta)\cdot M_x(\phi)\cdot \begin{bmatrix} X \\Y \\Z \end{bmatrix} \\= \begin{bmatrix} \cos\psi &-\sin\psi & 0 \\ \sin\psi &\cos\psi & 0\\ 0 & 0 &1 \end{bmatrix} \begin{bmatrix} \cos\theta &0 &\sin\theta\\ 0 & 1 &0\\ -\sin\theta &0 &\cos\theta\\ \end{bmatrix} \begin{bmatrix} 1 & 0 &0 \\ 0 &\cos\theta &-\sin\theta \\ 0 &\sin\theta &\cos\theta \end{bmatrix} \begin{bmatrix} X \\Y \\Z \end{bmatrix} \\= \begin{bmatrix} \cos\theta\cos\psi &-\cos\phi\sin\psi+\sin\phi\sin\theta\cos\psi &\sin\phi\sin\psi+\cos\phi\sin\theta\cos\psi \\ \cos\theta\sin\psi &\cos\phi\cos\psi+\sin\phi\sin\theta\sin\psi &-\sin\phi\cos\psi+\cos\phi\sin\theta\sin\psi \\ -\sin\theta &\sin\phi\cos\theta &\cos\phi\cos\theta \end{bmatrix} \begin{bmatrix} X \\Y \\Z \end{bmatrix} \qquad(1) ⎣⎡xyz⎦⎤=M(ψ,θ,ϕ)⎣⎡XYZ⎦⎤=Mz(ψ)⋅My(θ)⋅Mx(ϕ)⋅⎣⎡XYZ⎦⎤=⎣⎡cosψsinψ0−sinψcosψ0001⎦⎤⎣⎡cosθ0−sinθ010sinθ0cosθ⎦⎤⎣⎡1000cosθsinθ0−sinθcosθ⎦⎤⎣⎡XYZ⎦⎤=⎣⎡cosθcosψcosθsinψ−sinθ−cosϕsinψ+sinϕsinθcosψcosϕcosψ+sinϕsinθsinψsinϕcosθsinϕsinψ+cosϕsinθcosψ−sinϕcosψ+cosϕsinθsinψcosϕcosθ⎦⎤⎣⎡XYZ⎦⎤(1)
旋转矩阵M(ψ,θ,ϕ)M(\psi,\theta,\phi)M(ψ,θ,ϕ)是将点P在相机坐标系中的坐标分量转换到相机旋转前的原坐标系中的坐标分量。
Cesium中,使用Matrix3对象表示3×3矩阵,其中表示相机HeadingPitchRoll的旋转矩阵(M(ψ,θ,ϕ)M(\psi,\theta,\phi)M(ψ,θ,ϕ))代码如下:
/*** Computes a 3x3 rotation matrix from the provided headingPitchRoll. (see http://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles )** @param {HeadingPitchRoll} headingPitchRoll the headingPitchRoll to use.* @param {Matrix3} [result] The object in which the result will be stored, if undefined a new instance will be created.* @returns {Matrix3} The 3x3 rotation matrix from this headingPitchRoll.*/Matrix3.fromHeadingPitchRoll = function(headingPitchRoll, result) {//>>includeStart('debug', pragmas.debug);Check.typeOf.object('headingPitchRoll', headingPitchRoll);//>>includeEnd('debug');// 注意此处,为了使用正常的321转序,此处需将heding和pitch的角度加上负号var cosTheta = Math.cos(-headingPitchRoll.pitch);var cosPsi = Math.cos(-headingPitchRoll.heading);var cosPhi = Math.cos(headingPitchRoll.roll);var sinTheta = Math.sin(-headingPitchRoll.pitch);var sinPsi = Math.sin(-headingPitchRoll.heading);var sinPhi = Math.sin(headingPitchRoll.roll);// 第1行矩阵元素var m00 = cosTheta * cosPsi;var m01 = -cosPhi * sinPsi + sinPhi * sinTheta * cosPsi;var m02 = sinPhi * sinPsi + cosPhi * sinTheta * cosPsi;// 第2行矩阵元素var m10 = cosTheta * sinPsi;var m11 = cosPhi * cosPsi + sinPhi * sinTheta * sinPsi;var m12 = -sinPhi * cosPsi + cosPhi * sinTheta * sinPsi;// 第3行矩阵元素var m20 = -sinTheta;var m21 = sinPhi * cosTheta;var m22 = cosPhi * cosTheta;if (!defined(result)) {return new Matrix3(m00, m01, m02,m10, m11, m12,m20, m21, m22);}result[0] = m00;result[1] = m10;result[2] = m20;result[3] = m01;result[4] = m11;result[5] = m21;result[6] = m02;result[7] = m12;result[8] = m22;return result;};
四元素的表示
参考Cesium中的相机—四元素一文中连续旋转的四元素乘法规则,相机从原坐标系o−xyzo-xyzo−xyz历经321(ZYX)三次旋转的四元素表示为:
q(ψ,θ,ϕ)=qz(ψ)⋅qy(θ)⋅qx(ϕ)=[cos(ψ/2)00sin(ψ/2)][cos(θ/2)0sin(θ/2)0][cos(ϕ/2)sin(ϕ/2)00]=[cos(ϕ/2)cos(θ/2)cos(ψ/2)+sin(ϕ/2)sin(θ/2)sin(ψ/2)sin(ϕ/2)cos(θ/2)cos(ψ/2)−cos(ϕ/2)sin(θ/2)sin(ψ/2)cos(ϕ/2)sin(θ/2)cos(ψ/2)+sin(ϕ/2)cos(θ/2)sin(ψ/2)cos(ϕ/2)cos(θ/2)sin(ψ/2)−sin(ϕ/2)sin(θ/2)cos(ψ/2)](2)q(\psi,\theta,\phi)=q_z(\psi)\cdot q_y(\theta) \cdot q_x(\phi)= \begin{bmatrix}\cos(\psi/2) \\0 \\0 \\ \sin(\psi/2) \end{bmatrix} \begin{bmatrix}\cos(\theta/2) \\0 \\ \sin(\theta/2) \\0 \end{bmatrix} \begin{bmatrix}\cos(\phi/2) \\ \sin(\phi/2) \\0 \\0 \end{bmatrix} \\= \begin{bmatrix} \cos(\phi/2)\cos(\theta/2)\cos(\psi/2)+\sin(\phi/2)\sin(\theta/2)\sin(\psi/2)\\ \sin(\phi/2)\cos(\theta/2)\cos(\psi/2)-\cos(\phi/2)\sin(\theta/2)\sin(\psi/2)\\ \cos(\phi/2)\sin(\theta/2)\cos(\psi/2)+\sin(\phi/2)\cos(\theta/2)\sin(\psi/2)\\ \cos(\phi/2)\cos(\theta/2)\sin(\psi/2)-\sin(\phi/2)\sin(\theta/2)\cos(\psi/2) \end{bmatrix} \qquad(2)q(ψ,θ,ϕ)=qz(ψ)⋅qy(θ)⋅qx(ϕ)=⎣⎢⎢⎡cos(ψ/2)00sin(ψ/2)⎦⎥⎥⎤⎣⎢⎢⎡cos(θ/2)0sin(θ/2)0⎦⎥⎥⎤⎣⎢⎢⎡cos(ϕ/2)sin(ϕ/2)00⎦⎥⎥⎤=⎣⎢⎢⎡cos(ϕ/2)cos(θ/2)cos(ψ/2)+sin(ϕ/2)sin(θ/2)sin(ψ/2)sin(ϕ/2)cos(θ/2)cos(ψ/2)−cos(ϕ/2)sin(θ/2)sin(ψ/2)cos(ϕ/2)sin(θ/2)cos(ψ/2)+sin(ϕ/2)cos(θ/2)sin(ψ/2)cos(ϕ/2)cos(θ/2)sin(ψ/2)−sin(ϕ/2)sin(θ/2)cos(ψ/2)⎦⎥⎥⎤(2)
上式中,qz(ψ)q_z(\psi)qz(ψ)表示绕Z轴旋转ψ\psiψ角度的四元素,其它类似。
参考Cesium中的相机—四元素文中式(5),将四元素q(ψ,θ,ϕ)q(\psi,\theta,\phi)q(ψ,θ,ϕ)可表示为旋转矩阵,则本文中,式(1)和式(2)相等。
Cesium中,使用对象Quaternion表示四元素,则由表示相机HeadingPitchRoll的表示的四元素源代码如下:
// 临时四元素对象存储var scratchHPRQuaternion = new Quaternion();var scratchHeadingQuaternion = new Quaternion();var scratchPitchQuaternion = new Quaternion();var scratchRollQuaternion = new Quaternion();/*** Computes a rotation from the given heading, pitch and roll angles. Heading is the rotation about the* negative z axis. Pitch is the rotation about the negative y axis. Roll is the rotation about* the positive x axis.** @param {HeadingPitchRoll} headingPitchRoll The rotation expressed as a heading, pitch and roll.* @param {Quaternion} [result] The object onto which to store the result.* @returns {Quaternion} The modified result parameter or a new Quaternion instance if none was provided.*/Quaternion.fromHeadingPitchRoll = function(headingPitchRoll, result) {//>>includeStart('debug', pragmas.debug);Check.typeOf.object('headingPitchRoll', headingPitchRoll);//>>includeEnd('debug');// 注意此处,为了使用正常的321转序,此处需将heding和pitch的角度加上负号// 最终的四元素=qz•qy•qxscratchRollQuaternion = Quaternion.fromAxisAngle(Cartesian3.UNIT_X, headingPitchRoll.roll, scratchHPRQuaternion);scratchPitchQuaternion = Quaternion.fromAxisAngle(Cartesian3.UNIT_Y, -headingPitchRoll.pitch, result);result = Quaternion.multiply(scratchPitchQuaternion, scratchRollQuaternion, scratchPitchQuaternion);scratchHeadingQuaternion = Quaternion.fromAxisAngle(Cartesian3.UNIT_Z, -headingPitchRoll.heading, scratchHPRQuaternion);return Quaternion.multiply(scratchHeadingQuaternion, result, result);};
小结
Cesium中,使用Heading /Pitch /Roll来分别表示相机坐标系绕Z、Y、X轴的3次连续旋转,需要注意的是,Heading和Pitch的旋转角度与普通右手旋转的符号相反,因此在计算中需要在前两个角度加上负号,再进行321转序的旋转。
Cesium采用的是第二种旋转方式,因此连续旋转时,最先旋转的矩阵(或四元素)在最左边。
由HeadingPitchRoll创建的旋转矩阵Matrix3(或者四元素表示的)是把相机坐标系中的点坐标转换为原坐标系中(不一定是世界坐标系)的坐标。
Cesium中的相机—HeadingPitchRoll相关推荐
- Cesium中的相机—旋转矩阵
在学习坐标旋转的时候,一不小心就会把坐标系的旋转和矢量的旋转弄错,这里给出详细的两种旋转过程: 两种旋转矩阵的定义 下面仅以绕Z轴旋转为例,给出两种旋转的过程定义. 坐标系旋转,点不变(见下左图) 两 ...
- Cesium中的相机—YawPitchRoll
原博文地址:https://blog.csdn.net/u011575168/article/details/83097894 以正前方为X轴,以左手坐标系建立O_XYZ坐标系.Yaw.Pitch.R ...
- Cesium 中两种添加 model 方法的区别
概述 Cesium 中包含两种添加 model 的方法,分别为: 通过 viewer.entities.add() 函数添加 通过 viewer.scene.primitives.add() 函数添加 ...
- Cesium中添加entitie模型,实现贴地。
1.Cesium中添加entitie模型,实现贴地. 2. 添加模型 const createModel = (url) => {const entity = viewer.entities.a ...
- Cesium 中的离屏渲染
Cesium 中的离屏渲染 本文参考了众多文章,均列在了最后.先感谢各位的分享精神,如觉有冒犯,请与我联系. 部分内容来自个人理解,欢迎指正交流. 为了达到更加真实的渲染效果或其他计算需求,很多时候需 ...
- Cesium中自定义材质material
文章转自: https://blog.csdn.net/weixin_38676065/article/details/126123975 学习参考文章:https://github.com/Anal ...
- 对比分析OSG与Cesium中模型LOD的异同
1. LOD 熟悉渲染的读者可能经常听到LOD(Level Of Detail),也就是用不同的细节层次来表达同一个对象.比如下图中的雕像,从左到右精细度越来越低,最后甚至仅剩一个轮廓,已经看不出人形 ...
- Vue集成Cesium之二 —— 相机(Camera)
上一篇文章初步写了一下 vue 集成 cesium 方法和注意的地方. 最近因为项目中用到的地图资源并不是拿来就能用,需要调整显示的角度.缩放等设置.所以把 cesium 所有的相机(也就是视角)设置 ...
- GIS数据处理-cesium中模型位置设置
GIS数据处理-cesium中模型位置设置 介绍 最近我收到不少人私信询问我,在cesium中加载3dtiles模型后如何调整模型位置,这里我就统一的介绍一下,我是怎么处理的以供大家参考. 常见模型分 ...
最新文章
- UPDATE STATISTICS 有何妙用?
- 编写优质代码的 6 大关键方法
- java中 抽象类+接口
- Scikit-learn使用总结
- TCP/IP详解学习笔记(13)-TCP坚持定时器,TCP保活定时器
- 【面试招聘】非科班小白上岸的学习路线
- boost::container模块实现全部分配的测试程序
- 发布代码小助手V2.1发布了——Code2HTML工具
- 微信公众平台消息接口开发之校验签名与消息响应合并
- 就算不偷盗,也让你看看计算机里常用的有那些软件--常用软件序列号
- matlab画圆的命令_matlab画圆命令资料
- python编程基础-上海交通大学版答案
- 【STM32】两轮自平衡小车学习笔记2
- Android Studio稀奇古怪的疑难杂症
- Codeforces-1682B: AND Sorting 【构造、排序、位运算】
- java7 调优_JVM故障分析及性能优化系列之七:使用MAT的Histogram和Dominator Tree定位溢出源...
- hduoj 一只小蜜蜂
- FP-Tree算法的实现
- 技术分享:2.0mm小间距多接枝刚挠结合板制作工艺研究
- spreadsheetControl
热门文章
- Android 模拟游戏手柄按键(跨进程 KeyEvent 事件)实践方案
- 比赛题目训练系列17 (2020-2021 ACM-ICPC Brazil Subregional Programming Contest)
- element若依 菜单点击改变背景色
- Out of memory: Kill process 解决
- Week 5.1 | 左倾红黑树LLRB | Princeton Algorithms
- Robert Sedgewick左倾红黑树论文翻译
- GPU架构杂乱备忘——IMR、TBR、TBDR
- 在线免费网盘空间统计
- 《Python数据分析基础教程:NumPy学习指南(第2版)》笔记1:第一章 NumPy快速入门
- launchOptions利用userActivity呼起app设置