zoukankan      html  css  js  c++  java
  • 三维几何中的旋转表示:四元数、欧拉角和旋转矩阵

    在三维几何中,有三种用于表示旋转的方式,它们分别是四元数、欧拉角和旋转矩阵。本文将对它们的概念以及运算进行讲解。

    本文全部基于左手坐标系进行讨论。

    欧拉角

    欧拉角用三个角度来描述物体的旋转,这三个角度又被称为roll-pitch-yaw,它们分别代表着物体绕z、x和y轴进行的旋转,其中roll又被称为bank,yaw又被称为heading。通过将三个轴的旋转组合起来,就可以得到最终的旋转结果。因此,不同的旋转顺序所得到的的结果是不同的,这一点需要万分注意。

    为了避免欧拉角给定方位的表达式不唯一的问题,我们将欧拉角的数值限制在一定范围以内,称作限制欧拉角。一般将heading和bank限定在[-180,180]度之间,pitch限制在[-90,90]度之间;为了避免万向锁问题,规定万向锁情况下由heading完成绕竖直轴的全部旋转,也就是在限制欧拉角下,如果pitch为+90或-90,则bank为零。

    关于万向锁可以参考这篇文章:

    https://blog.csdn.net/qq_35957011/article/details/77188036

    另外,根据欧拉角对物体进行旋转时,需要考虑所绕的轴是内在(intrinsic)的还是外在(extrinsic)的,“内在”的意思是绕着世界坐标系的坐标轴进行旋转;“外在”的意思是绕着物体本身局部坐标系的坐标轴进行旋转(前提是在旋转前物体自身的坐标系与世界坐标轴是一致的)。需要注意的一点是,如果是外在旋转的话,相当于按相反顺序的轴用内在的方式进行旋转。也就是说如果是让该物体绕自身坐标系按xyz轴的顺序旋转,则相当于将该物体按世界坐标系按zyx轴旋转。

    四元数

    相比于欧拉角,四元数采用四个数值来表达物体的旋转,一般记为[x,y,z,w],代表了复数w+xi+yj+zk。可以利用它来代表旋转:设物体的方位为绕着n轴旋转θ角度,则可设:[x,y,z,w] = [sin(θ/2)nx,sin(θ/2)ny,sin(θ/2)nz,cos(θ/2)]。这样就可以表达旋转了,我们设这样的四元数为q

    四元数有它自己的旋转公式:

    (1)

    根据四元数表达旋转的意义可知,q和-q所代表的的实际角位移是相等的。

    设单位四元数为[0,0,0,1],任意四元数q乘以单位四元数均为它本身;若乘以[0,0,0,-1]则得到-q

    假设知道了一个三维顶点(x,y,z)和代表旋转的四元数q,我们可以用四元数乘法来计算出按照q旋转后的点p'

    p' = qpq-1

    其中p=[x,y,z,0], p'为四维向量,且q的旋转轴必须是单位向量

    四元数乘法可以连接多次旋转。举个例子,设两个四元数a和b,先进行a旋转再进行b旋转等价于进行ba所代表的旋转。

    相比于欧拉角,四元数有一个特别的优点:可以很方便地做两个四元数之间的插值,该插值算法叫做slerp插值(Spherical Linear Interpolation)。在这里我们隐去推导过程,直接上公式:

            (2) 

    其中t代表插值的比例,ω代表两个四元数之间的夹角(可以通过点乘计算得出)。为了防止出现数值误差,当sinω非常小时可以直接使用简单的线性插值。

    旋转矩阵

    除了四元数和欧拉角,也可用矩阵的形式来代表旋转。一般3*3的矩阵就可以表示3维空间中任意的旋转了。

    设旋转轴为(x,y,z),旋转角度为θ,我们设c=cosθ,s=sinθ,那么可以得到绕任意轴的旋转矩阵:

           (3)

    绕着单个轴的旋转矩阵如下:

    (4)

    欧拉角、四元数和旋转矩阵之间的转换

    欧拉角转换到旋转矩阵

    欧拉角转换到旋转矩阵的方法比较简单,直接上旋转矩阵的叠加就可以,这里列出内在形式下按照zxy轴顺序的计算公式:

      (5)

    旋转矩阵转换到欧拉角

    从旋转矩阵转换到欧拉角需要注意将roll、pitch、bank限定在限制欧拉角的范围以内。假设要通过上一小节的旋转矩阵推导出zxy轴内在形式下的欧拉角,可以这么去做:

    设上一小节推导出的矩阵为M,M(1,1)代表矩阵最左上角的项,那么首先可以得到pitch = asin(-M(3,2))。(直接调用C语言内置的函数,范围正好在[-90°,90°]之间)

    如果|pitch|为90°,那么按照限定欧拉角的做法,roll此时为0, yaw = atan2(-M(1,3), M(1, 1)) (利用C语言内置的atan2函数,正好可以将范围限制在[-180°,180°]之间)

    如果|pitch|不是90°,我们可以推导roll和yaw为:

    roll = atan2(M(1, 2), M(2, 2))
    yaw = atan2(M(3, 1), M(3, 3))

    如果是外在或者其他坐标轴的顺序,推导方法也是大同小异。

    四元数转换到旋转矩阵

    四元数中记载了旋转轴和旋转角度,那么我们可以通过这些信息根据公式(3)推导出旋转矩阵。

    但其实还是有更直接的推导方式,在这里给出结论,已知四元数(x,y,z,w),我们可以得到旋转矩阵:

    (6)

    旋转矩阵转换到四元数

    想将旋转矩阵转换为四元数,可以检查相对于对角线的对称位置上元素的和与差:

    (7)

    然后可以先用对角线元素和/差的平方根解得四个值中的一个,就能用公式(7)去计算其他三个:

    (8)

    那么应当用这四种解法中的哪一个呢?Shoemake建议取计算出的w,x,y,z最大的一个(不必解平方根),然后再计算出其他三个,这样可以避免由于分母太小导致的数值不稳定问题。

    这种方法不用在意求解的平方根的正负,因为四元数q和-q在旋转方位上是等价的。

    欧拉角转换到四元数

    从欧拉角转换到四元数,可以将欧拉角的三个旋转都转换为四元数,然后将这三个四元数连接为一个四元数即可。

    四元数转换到欧拉角

     通过旋转矩阵转换到欧拉角的过程,可以得:

    (9)

    而已知:

    M(3,2) = 2yz - 2wx

    M(1,2) = 2xy + 2wz

    M(2,2) = 1 - 2x^2 - 2z^2

    M(3,1) = 2xz + 2wy

    M(3,3) = 1 - 2x^2 - 2y^2

    M(1,3) = 2xz - 2wy

    M(1,1) = 1 - 2y^2 - 2z^2

    带入(9)中可得:

    (10)

    参考文献:《3D数学基础:图形与游戏开发》 第10章

  • 相关阅读:
    ELK Packetbeat 部署指南
    ELK beats平台介绍
    ELK Packetbeat 部署指南(15th)
    什么是staging server
    elasticsearch学习一、安装和配置
    How To Use Logstash and Kibana To Centralize Logs On CentOS 6
    Java字节码(.class文件)格式详解(一)
    JVM之字节码——Class文件格式
    如何获得JVM执行过程中调用的方法名
    ELK beats通用配置说明(12th)
  • 原文地址:https://www.cnblogs.com/wickedpriest/p/11151675.html
Copyright © 2011-2022 走看看