热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

欧拉角与四元数(计算,编程)

欧拉角四元数计算公式四元数的基本数学方程为:qcos(a2)+i(x*sin(a2))+j(y*sin(a2))+k(z*sin(a2))

欧拉角

 

四元数计算公式

四元数的基本数学方程为 : q = cos (a/2) + i(x * sin(a/2)) + j(y * sin(a/2)) + k(z * sin(a/2)) 其中a表示旋转角度,(x,y,z)表示旋转轴

 
下面是如何把具体的四元数与旋转轴和旋转角度对应起来。
    1.指出旋转轴和旋转角度,如何转化为四元素。
    假定旋转轴是:RAxis = Z轴,换算成三维空间单位向量就是RAxis = [0 0 1],旋转60度
    那么转化成四元数就是
    q.w=cos(60°/2) = 0.866
    q.x=RAix.x*sin(60°/2) = 0*0.5=0
    q.y=RAix.y*sin(60°/2) = 0*0.5=0
    q.z=RAix.z*sin(60°/2) = 1*0.5=0.5
    例子验证:从三维空间中看,假定物体点A=[0 1 0],绕 RAxis = Z轴,旋转30度(假定顺时针为正,因为matlab就是顺时针为正,而下面的quat2dcm函数是matlab自带的)
那么物体点A旋转后在世界坐标系下的坐标将是B=[0.866 0.5 0],
如何用四元数计算出呢?思路是这样的:任何一个四元数对应着一个旋转3*3矩阵。
M=quat2dcm(q)*A'=[0.866;0.5;0],关于quat2dcm在软件matlab里面有。
 
四元数编程
四元数的一种表示方式是: Q = xi + yj + zk + w

这儿i,  j,  k就可以看成3D 空间的3个坐标柱向量。  基于四元数的这种表示方式所以很直接他就可以被表示成一个标量w
再加上一个3维向量了。

Q = [w, v]

这里 v = xi + yj + zk

自然有一定编程经验的人会立即把这个小家伙用结构体来表示了如下:
struct quaternion
{
       double x, y, z, w;
}
这里我们没必要知道四元数的加减运算法则了,现在为了解决我们的目标(创建基于四元数的摄像机)我们第一步需要知道怎样把他标准化
。四元数的标准化和向量的标准化是一样的。目的都是将模变成1. |Q| = sqrt(w^2 + x^2 +y^2 + z^2)
下面是代码
double getLength(quaternion quat)
{
       return sqrt(quat.x * quat.x + quat.y * quat.y + quat.z * quat.z + quat.w * quat.w);
}

标准化的四元数 Q* = Q/|Q| = [w/|Q|, v/|Q|];
这儿是代码:
quaternion normalize(quaternion quat)
{
       double Length = length(quat);
       quat.x /= Length;
       quat.y /= Length;
       quat.z /= Lenght;
       quat.w /= Length;
       return quat;
}
下来我们需要知道怎样计算一个四元数的共轭四元数, 共轭四元数暂且用Q' 来代替吧。
Q' = [w, -v]
这儿是计算共轭四元数的代码:
quaternion conjugate(quaternion quat)
{
       quat.x = -quat.x;
       quat.y = -quat.y;
       quat.z = -quat.z;
       quat.w = -quat.w;
       return quat;
}
下面的事情就是看看怎样计算四元数的成绩了,这个貌似有点小小的复杂。
假设有四元数C , A , B 现在我们要计算 C= A* B;
具体的运算规则如下:
C.x = |A.w * B.x + A.x * B.w + A.y * B.z - A.z * B.y|
C.y = |A.w * B.y - A.x * B.z + A.y * B.w + A.z * B.x|
C.z = |A.w * B.z + A.x * B.y - A.y * B.x + A.z * B.w|
C.w = |A.w * B.w - A.x * B.x - A.y * B.y - A.z * B.z|
这儿是代码:
quaternion mult(quaternion quat)
{
      quaternion C;
      C.x = A.w*B.x + A.x*B.w + A.y*B.z - A.z*B.y;
      C.y = A.w*B.y - A.x*B.z + A.y*B.w + A.z*B.x;
      C.z = A.w*B.z + A.x*B.y - A.y*B.x + A.z*B.w;
      C.w = A.w*B.w - A.x*B.x - A.y*B.y - A.z*B.z;
      return C;
}
主要的运算讲完了,下面就要进入正题了。 现在我们是要创建摄像机了请注意。很明显在3D空间里面代表一个摄像机
就需要对这个摄像机进行定位,定向了。所以为了精确的创建摄像机,我们使用3个3维向量来代表摄像机的位置Position,观察方向View,
和摄像机的UP(这个没必要介绍吧)。对于一个第一人称的摄像机来说,我们现在就只需要考虑摄像机的旋转问题了,
使用四元数我们就可以把一个向量绕任意的柱旋转, 为了达到这个目的我们就需要首先将View向量转化成四元数,然后定义一个旋转四元数,最后应用这个旋转四元数到View四元数上就行了。下面请看具体的步骤。
为了获得View四元数,我们就要使用[w, v]来代表了。当然标量w 就设成0了。v 很显然就是View向量了。
因此四元数V(我们转化的View四元数) V = [0, View]
然后正如上面所说我们下面就要创建那个旋转四元数了,为了创建这个四元数,你就得明确你要绕哪个向量旋转了,还有旋转的角度。我们把这个柱向量(就是绕哪个向量旋转)叫做A,把旋转的角度用theta表示,那么任务即将完成了,我们创建的旋转四元数R就可以表示成:
3DVector A = [x, y , z];
R.x = A.x * sin(theta/2);
R.y = A.y * sin(theta/2);
R.z = A.z * sin(theta/2);
R.w = cos(theta/2);
下来就要进行旋转计算了:
先看看我们现在知道的量:
1. 我们有3维的View向量, 我们有View四元数 V = [0, View]
2. 假设我们要绕A向量来旋转theta度,我们有旋转四元数R来定义这次旋转。
3. 记住旋转完后我们得到的东西仍然是一个View四元数,这个自然是个新的View四元数了。我们假设他是W
所以旋转操作就是:
W = R * V * R'
这里R是旋转四元数, V是View四元数, R' 是旋转四元数R的共轭四元数(其运算前面以讲了)
现在我们仅仅提取新的View四元数W的向量部分。 NewView = [W.x, W.y, W.z]
所以综上所述我们就可以创建函数来进行旋转变换:
void RotateCamera(float angle, float x, float y, float z)
{
       quaternion temp, quat_view, result;// quat_view是View四元数, temp是旋转四元数
     //  下面的三行使用旋转柱和角度计算旋转四元数
       temp.x = x * sin(angle/2);
       temp.y = y * sin(angle/2);
       temp.z = z * sin(angle/2);
       temp.w = cos(angle/2);
       // 计算View四元数
       quat_view.x = View.x; // View 是View向量
       quat_view.y = View.y;
       quat_view.z = View.z;
       quat_view.w = 0;
       //  进行旋转变换
       result = mult(mult(temp, qaut_view), conjugate(temp));
       // 得到新的View向量
       View.x = result.x;
       View.y = result.y;
       View.z = result.z;
}
至此完成。相信有一定OpenGL或D3D基础的人,很容易就把这个翻译成代码了。

 


推荐阅读
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • 自动轮播,反转播放的ViewPagerAdapter的使用方法和效果展示
    本文介绍了如何使用自动轮播、反转播放的ViewPagerAdapter,并展示了其效果。该ViewPagerAdapter支持无限循环、触摸暂停、切换缩放等功能。同时提供了使用GIF.gif的示例和github地址。通过LoopFragmentPagerAdapter类的getActualCount、getActualItem和getActualPagerTitle方法可以实现自定义的循环效果和标题展示。 ... [详细]
  • 本文介绍了闭包的定义和运转机制,重点解释了闭包如何能够接触外部函数的作用域中的变量。通过词法作用域的查找规则,闭包可以访问外部函数的作用域。同时还提到了闭包的作用和影响。 ... [详细]
  • 生成式对抗网络模型综述摘要生成式对抗网络模型(GAN)是基于深度学习的一种强大的生成模型,可以应用于计算机视觉、自然语言处理、半监督学习等重要领域。生成式对抗网络 ... [详细]
  • 云原生边缘计算之KubeEdge简介及功能特点
    本文介绍了云原生边缘计算中的KubeEdge系统,该系统是一个开源系统,用于将容器化应用程序编排功能扩展到Edge的主机。它基于Kubernetes构建,并为网络应用程序提供基础架构支持。同时,KubeEdge具有离线模式、基于Kubernetes的节点、群集、应用程序和设备管理、资源优化等特点。此外,KubeEdge还支持跨平台工作,在私有、公共和混合云中都可以运行。同时,KubeEdge还提供数据管理和数据分析管道引擎的支持。最后,本文还介绍了KubeEdge系统生成证书的方法。 ... [详细]
  • 本文介绍了设计师伊振华受邀参与沈阳市智慧城市运行管理中心项目的整体设计,并以数字赋能和创新驱动高质量发展的理念,建设了集成、智慧、高效的一体化城市综合管理平台,促进了城市的数字化转型。该中心被称为当代城市的智能心脏,为沈阳市的智慧城市建设做出了重要贡献。 ... [详细]
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • [译]技术公司十年经验的职场生涯回顾
    本文是一位在技术公司工作十年的职场人士对自己职业生涯的总结回顾。她的职业规划与众不同,令人深思又有趣。其中涉及到的内容有机器学习、创新创业以及引用了女性主义者在TED演讲中的部分讲义。文章表达了对职业生涯的愿望和希望,认为人类有能力不断改善自己。 ... [详细]
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
  • C# 7.0 新特性:基于Tuple的“多”返回值方法
    本文介绍了C# 7.0中基于Tuple的“多”返回值方法的使用。通过对C# 6.0及更早版本的做法进行回顾,提出了问题:如何使一个方法可返回多个返回值。然后详细介绍了C# 7.0中使用Tuple的写法,并给出了示例代码。最后,总结了该新特性的优点。 ... [详细]
  • sklearn数据集库中的常用数据集类型介绍
    本文介绍了sklearn数据集库中常用的数据集类型,包括玩具数据集和样本生成器。其中详细介绍了波士顿房价数据集,包含了波士顿506处房屋的13种不同特征以及房屋价格,适用于回归任务。 ... [详细]
  • C# WPF自定义按钮的方法
    本文介绍了在C# WPF中实现自定义按钮的方法,包括使用图片作为按钮背景、自定义鼠标进入效果、自定义按压效果和自定义禁用效果。通过创建CustomButton.cs类和ButtonStyles.xaml资源文件,设计按钮的Style并添加所需的依赖属性,可以实现自定义按钮的效果。示例代码在ButtonStyles.xaml中给出。 ... [详细]
  • Go GUIlxn/walk 学习3.菜单栏和工具栏的具体实现
    本文介绍了使用Go语言的GUI库lxn/walk实现菜单栏和工具栏的具体方法,包括消息窗口的产生、文件放置动作响应和提示框的应用。部分代码来自上一篇博客和lxn/walk官方示例。文章提供了学习GUI开发的实际案例和代码示例。 ... [详细]
  • 本文讨论了clone的fork与pthread_create创建线程的不同之处。进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合。在调用系统调用fork创建一个进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性。但是二者之间的通讯需要通过专门的通讯机制,另外通过fork创建子进程系统开销很大。因此,在某些情况下,使用clone或pthread_create创建线程可能更加高效。 ... [详细]
author-avatar
min-章_998
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有