Quaternion(四元数)和旋转以及Yaw, pitch, roll 的含义

article/2025/10/31 2:41:59
原文: http://www.linuxgraphics.cn/graphics/opengl_quaternion.html
Quaternion(四元数)和旋转

本文介绍了四元数以及如何在OpenGL中使用四元数表示旋转。

Quaternion 的定义

四元数一般定义如下:

    q=w+xi+yj+zk

其中 w,x,y,z是实数。同时,有:

    i*i=-1j*j=-1k*k=-1

四元数也可以表示为:

    q=[w,v]

其中v=(x,y,z)是矢量,w是标量,虽然v是矢量,但不能简单的理解为3D空间的矢量,它是4维空间中的的矢量,也是非常不容易想像的。

通俗的讲,一个四元数(Quaternion)描述了一个旋转轴和一个旋转角度。这个旋转轴和这个角度可以通过 Quaternion::ToAngleAxis转换得到。当然也可以随意指定一个角度一个旋转轴来构造一个Quaternion。这个角度是相对于单位四元数而言的,也可以说是相对于物体的初始方向而言的。

当用一个四元数乘以一个向量时,实际上就是让该向量围绕着这个四元数所描述的旋转轴,转动这个四元数所描述的角度而得到的向量。

四元组的优点1

有多种方式可表示旋转,如 axis/angle、欧拉角(Euler angles)、矩阵(matrix)、四元组等。 相对于其它方法,四元组有其本身的优点:

  • 四元数不会有欧拉角存在的 gimbal lock 问题
  • 四元数由4个数组成,旋转矩阵需要9个数
  • 两个四元数之间更容易插值
  • 四元数、矩阵在多次运算后会积攒误差,需要分别对其做规范化(normalize)和正交化(orthogonalize),对四元数规范化更容易
  • 与旋转矩阵类似,两个四元组相乘可表示两次旋转

Quaternion 的基本运算1

Normalizing a quaternion
// normalising a quaternion works similar to a vector. This method will not do anything
// if the quaternion is close enough to being unit-length. define TOLERANCE as something
// small like 0.00001f to get accurate results
void Quaternion::normalise()
{// Don't normalize if we don't have tofloat mag2 = w * w + x * x + y * y + z * z;if (  mag2!=0.f && (fabs(mag2 - 1.0f) > TOLERANCE)) {float mag = sqrt(mag2);w /= mag;x /= mag;y /= mag;z /= mag;}
}
The complex conjugate of a quaternion
// We need to get the inverse of a quaternion to properly apply a quaternion-rotation to a vector
// The conjugate of a quaternion is the same as the inverse, as long as the quaternion is unit-length
Quaternion Quaternion::getConjugate()
{return Quaternion(-x, -y, -z, w);
}
Multiplying quaternions
// Multiplying q1 with q2 applies the rotation q2 to q1
Quaternion Quaternion::operator* (const Quaternion &rq) const
{// the constructor takes its arguments as (x, y, z, w)return Quaternion(w * rq.x + x * rq.w + y * rq.z - z * rq.y,w * rq.y + y * rq.w + z * rq.x - x * rq.z,w * rq.z + z * rq.w + x * rq.y - y * rq.x,w * rq.w - x * rq.x - y * rq.y - z * rq.z);
}
Rotating vectors
// Multiplying a quaternion q with a vector v applies the q-rotation to v
Vector3 Quaternion::operator* (const Vector3 &vec) const
{Vector3 vn(vec);vn.normalise();Quaternion vecQuat, resQuat;vecQuat.x = vn.x;vecQuat.y = vn.y;vecQuat.z = vn.z;vecQuat.w = 0.0f;resQuat = vecQuat * getConjugate();resQuat = *this * resQuat;return (Vector3(resQuat.x, resQuat.y, resQuat.z));
}

How to convert to/from quaternions1

Quaternion from axis-angle
// Convert from Axis Angle
void Quaternion::FromAxis(const Vector3 &v, float angle)
{float sinAngle;angle *= 0.5f;Vector3 vn(v);vn.normalise();sinAngle = sin(angle);x = (vn.x * sinAngle);y = (vn.y * sinAngle);z = (vn.z * sinAngle);w = cos(angle);
}
Quaternion from Euler angles
// Convert from Euler Angles
void Quaternion::FromEuler(float pitch, float yaw, float roll)
{// Basically we create 3 Quaternions, one for pitch, one for yaw, one for roll// and multiply those together.// the calculation below does the same, just shorterfloat p = pitch * PIOVER180 / 2.0;float y = yaw * PIOVER180 / 2.0;float r = roll * PIOVER180 / 2.0;float sinp = sin(p);float siny = sin(y);float sinr = sin(r);float cosp = cos(p);float cosy = cos(y);float cosr = cos(r);this->x = sinr * cosp * cosy - cosr * sinp * siny;this->y = cosr * sinp * cosy + sinr * cosp * siny;this->z = cosr * cosp * siny - sinr * sinp * cosy;this->w = cosr * cosp * cosy + sinr * sinp * siny;normalise();
}
Quaternion to Matrix
// Convert to Matrix
Matrix4 Quaternion::getMatrix() const
{float x2 = x * x;float y2 = y * y;float z2 = z * z;float xy = x * y;float xz = x * z;float yz = y * z;float wx = w * x;float wy = w * y;float wz = w * z;// This calculation would be a lot more complicated for non-unit length quaternions// Note: The constructor of Matrix4 expects the Matrix in column-major format like expected by//   OpenGLreturn Matrix4( 1.0f - 2.0f * (y2 + z2), 2.0f * (xy - wz), 2.0f * (xz + wy), 0.0f,2.0f * (xy + wz), 1.0f - 2.0f * (x2 + z2), 2.0f * (yz - wx), 0.0f,2.0f * (xz - wy), 2.0f * (yz + wx), 1.0f - 2.0f * (x2 + y2), 0.0f,0.0f, 0.0f, 0.0f, 1.0f)
}
Quaternion to axis-angle
// Convert to Axis/Angles
void Quaternion::getAxisAngle(Vector3 *axis, float *angle)
{float scale = sqrt(x * x + y * y + z * z);axis->x = x / scale;axis->y = y / scale;axis->z = z / scale;*angle = acos(w) * 2.0f;
}

Quaternion 插值2

线性插值

最简单的插值算法就是线性插值,公式如:

    q(t)=(1-t)q1 + t q2

但这个结果是需要规格化的,否则q(t)的单位长度会发生变化,所以

    q(t)=(1-t)q1+t q2 / || (1-t)q1+t q2 ||
球形线性插值

尽管线性插值很有效,但不能以恒定的速率描述q1到q2之间的曲线,这也是其弊端,我们需要找到一种插值方法使得q1->q(t)之间的夹角θ是线性的,即θ(t)=(1-t)θ1+t*θ2,这样我们得到了球形线性插值函数q(t),如下:

q(t)=q1 * sinθ(1-t)/sinθ + q2 * sinθt/sineθ

如果使用D3D,可以直接使用 D3DXQuaternionSlerp 函数就可以完成这个插值过程。

用 Quaternion 实现 Camera 旋转

总体来讲,Camera 的操作可分为如下几类:

  • 沿直线移动
  • 围绕某轴自转
  • 围绕某轴公转

下面是一个使用了 Quaternion 的 Camera 类:

    class Camera {private:Quaternion m_orientation;public:void rotate (const Quaternion& q);void rotate(const Vector3& axis, const Radian& angle);void roll (const GLfloat angle);void yaw (const GLfloat angle);void pitch (const GLfloat angle);};void Camera::rotate(const Quaternion& q){// Note the order of the mult, i.e. q comes afterm_Orientation = q * m_Orientation;}void Camera::rotate(const Vector3& axis, const Radian& angle){Quaternion q;q.FromAngleAxis(angle,axis);rotate(q);}void Camera::roll (const GLfloat angle) //in radian{Vector3 zAxis = m_Orientation * Vector3::UNIT_Z;rotate(zAxis, angleInRadian);}void Camera::yaw (const GLfloat angle)  //in degree{Vector3 yAxis;{// Rotate around local Y axisyAxis = m_Orientation * Vector3::UNIT_Y;}rotate(yAxis, angleInRadian);}void Camera::pitch (const GLfloat angle)  //in radian{Vector3 xAxis = m_Orientation * Vector3::UNIT_X;rotate(xAxis, angleInRadian);}void Camera::gluLookAt() {GLfloat m[4][4];identf(&m[0][0]);m_Orientation.createMatrix (&m[0][0]);glMultMatrixf(&m[0][0]);glTranslatef(-m_eyex, -m_eyey, -m_eyez);}

用 Quaternion 实现 trackball

用鼠标拖动物体在三维空间里旋转,一般设计一个 trackball,其内部实现也常用四元数。

class TrackBall
{
public:TrackBall();void push(const QPointF& p);void move(const QPointF& p);void release(const QPointF& p);QQuaternion rotation() const;private:QQuaternion m_rotation;QVector3D m_axis;float m_angularVelocity;QPointF m_lastPos;};void TrackBall::move(const QPointF& p)
{if (!m_pressed)return;QVector3D lastPos3D = QVector3D(m_lastPos.x(), m_lastPos.y(), 0.0f);float sqrZ = 1 - QVector3D::dotProduct(lastPos3D, lastPos3D);if (sqrZ > 0)lastPos3D.setZ(sqrt(sqrZ));elselastPos3D.normalize();QVector3D currentPos3D = QVector3D(p.x(), p.y(), 0.0f);sqrZ = 1 - QVector3D::dotProduct(currentPos3D, currentPos3D);if (sqrZ > 0)currentPos3D.setZ(sqrt(sqrZ));elsecurrentPos3D.normalize();m_axis = QVector3D::crossProduct(lastPos3D, currentPos3D);float angle = 180 / PI * asin(sqrt(QVector3D::dotProduct(m_axis, m_axis)));m_axis.normalize();m_rotation = QQuaternion::fromAxisAndAngle(m_axis, angle) * m_rotation;m_lastPos = p;}

Yaw, pitch, roll 的含义3

Yaw – Vertical axis:

yaw
yaw

Pitch – Lateral axis

pitch
pitch

Roll – Longitudinal axis

roll
roll

The Position of All three axes

Yaw Pitch Roll
Yaw Pitch Roll

http://chatgpt.dhexx.cn/article/vcuZHSTe.shtml

相关文章

Unity3d开发之对Quaternion的使用

上周找到了新公司。这周二来上班。可怕的是我刚去的第二天下午四点领导通知我做一个VRdemo,要求第二天交。我勒个擦。我现在对设备还没熟悉呢。连sdk都没下载而且距离上一次开发vr是在快两年之前了。属实让我措手不及。没错,按剧本走,加班到凌…

【Unity编程】四元数(Quaternion)与欧拉角

欧拉旋转、四元数、矩阵旋转之间的差异 除了欧拉旋转以外,还有两种表示旋转的方式:矩阵旋转和四元数旋转。接下来我们比较它们的优缺点。 欧拉角 优点:三个角度组成,直观,容易理解。优点:可以进行从一个方…

Quaternion类

Euler public static Quaternion Euler(float x, float y, float z); public static Quaternion Euler(Vector3 euler); 功能: 返回Quaternion对应的欧拉角 例子: public class ExampleClass : MonoBehaviour {public Quaternion rotation Quaternion.Euler(0, 30,…

Unity Quaternion

Quaternion 类的属性 eulerAngles 欧拉角 Quaternion 类的实例方法 1、SetFromToRotion 函数 2、SetLookRotation 函数 3、ToAngleAxis 函数 Quaternion 类的静态方法 1、Angle方法 2、Dot方法 3、Euler方法 4、FromToRotation方法 5、Inverse方法 6、Lerp方法 7…

【第018问 Unity中对Quaternion.AngleAxis的理解?】

一、背景 在游戏研发过程中,有时候会对一个物体经过多次围绕不同的轴进行不同角度的旋转,从而计算得到一个方向,以此来检测在该对应的方向上是否有对应的物体或别的对象,因此本节对Quaternion.AngleAxis进行简单的记录&#xff1…

Unity API详解——Quaternion类

Quaternion类又称四元数,由x、y、z和w这4个分量组成,属于struct类型。在Unity中,用Quaternion来存储和表示对象的旋转角度。Quaternion的变换比较复杂,对于GameObject一般的旋转及移动,可以用Transform中的相关方法实现…

Unity3D - 详解Quaternion类[转载]

一、简介 Quaternion又称四元数,由x,y,z和w这四个分量组成,是由爱尔兰数学家威廉卢云哈密顿在1843年发现的数学概念。四元数的乘法不符合交换律。从明确地角度而言,四元数是复数的不可交换延伸。如把四元数的集合考虑成多维实数空间的话&…

【Unity】Unity常用类:向量Vector3、四元数Quaternion

文章目录 Vector3构造函数静态变量变量运算符常用方法(静态)OrthoNormalize(正交标准化)Reflect(反射)Lerp(线性插值) Quaternion构造函数静态变量变量常用方法Eular(欧拉…

unity学习笔记——Quaternion(四元数)

本篇文章转自https://www.cnblogs.com/driftingclouds/p/6626183.html Quaternion类 Quaternion(四元数)用于计算Unity旋转。它们计算紧凑高效,不受万向节锁的困扰,并且可以很方便快速地进行球面插值。 Unity内部使用四元数来表…

【Unity编程】Unity中关于四元数的API详解

Unity中关于四元数的API详解 Quaternion类 Quaternion(四元数)用于计算Unity旋转。它们计算紧凑高效,不受万向节锁的困扰,并且可以很方便快速地进行球面插值。 Unity内部使用四元数来表示所有的旋转。 Quaternion是基于复数&am…

四元数快速入门【Quaternion】

四元数(Quaternion)是用于旋转和拉伸向量的数学运算符。 本文提供了一个概述,以帮助理解在空间导航等应用程序中对四元数的需求。 推荐:用 NSDT场景设计器 快速搭建3D场景。 可以通过多种方式在空间中准确定位、移动和旋转物体。 …

四元数(Quaternion)食用指南

四元数(Quaternion)食用指南 “这简直就是黑魔法!” 开发时,每次遇到旋转问题时总会心头一震,在欧拉角和四元数这两种处理方式的选择上犹豫不决,不知不觉就陷入了四元数的淤泥中…接下来,我决定…

Unity3D - 详解Quaternion类

一、简介 Quaternion又称四元数,由x,y,z和w这四个分量组成,是由爱尔兰数学家威廉卢云哈密顿在1843年发现的数学概念。四元数的乘法不符合交换律。从明确地角度而言,四元数是复数的不可交换延伸。如把四元数的集合考虑成多维实数空间的话&…

int 的最大值

int 的最大值 java int 类整数的最大值是 2 的 31 次方 - 1 2147483648 - 1 2147483647 可以用 Integer.MAX_VALUE 表示它,即 int value Integer.MAX_VALUE; Integer.MAX_VALUE 1 Integer.MIN_VALUE -2147483648 再大的数就要用 long (最大值 …

Python获取int最大值和float最大值

计算机所能表示的最大值,根据你的计算机的位数决定。有机计算机是64位,有的是32位,因此具体情况各不相同。本人的电脑是64位的。 1.获得int型的最大值 import sys MAX_INTsys.maxsize print(MAX_INT)2.获得float型的最大值 ##灰常简单 max…

C语言数据类型 int、long int 最大值

一、注意:前提是32位计算机: unsigned int 0~4294967295 int -2147483648~2147483647 unsigned long 0~4294967295 long -2147483648~2147483647 long long的最大值:9223372036854775807 long …

C++-int最大值

uint范围 0-255 int范围 -128 - 127 -2147483647 原码1111 1111 1111 1111 1111 1111 1111 1111-2147483647-1-2147483648;由于cpu里面存的是补码计算-2147483647  补码1000 0000 0000 0000 0000 0000 0000 0001-1       补码1111 1111 1111 1111 1111 1111 1111 11…

c语言求int的最大值最小值,c语言 int最大值是多少?

喵喔喔 int最大值,根据编译器类型不同而变化,具体如下:1、对于16位编译器,int占16位(2字节)。int的最大值为32767.2、对于32位和64位编译器,int占32位(4字节)。int的最大值为21474836473、可以通过打印sizeof(int)查看…

C语言|int型最大值和最小值

一.int型的最值 有符号 最小值:-2147483647-1最大值:2147483647 无符号 最大值:0xffffffff最小值:0 大家可以在整形类型的取值范围限制头文件中查看:limits.h 二.int型最小值的原因 当我们直接给int型变量赋-214748364…

软件测试管理神器之zentao(禅道)-BUG管理

软件测试管理神器之zentao(禅道)-BUG管理 禅道在遵循其管理方式基础上,结合国内研发现状,整合了bug管理,测试用例管理,发布管理,文档管理等功能,完整的覆盖了软件研发项目的整个生命周期。在禅道软件中&…