Flag Engine(动画系统)学习笔记(四)——“骨骼姿势”前篇之四元数

2023-10-12 05:20

本文主要是介绍Flag Engine(动画系统)学习笔记(四)——“骨骼姿势”前篇之四元数,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

2021SC@SDUSC

在上一节中学习了关于骨骼的数据结构,接下来我们会继续学习在动画系统中,骨骼是如何相对某参考系进行收收放,平移和旋转的。而这也被称为骨骼(关节)的姿势。

关节的姿势是通过SQT数据结构,一个4*3或4*4的矩阵表示(缩放,scale;四元数旋转,quaternion;矢量平移(方向,距离(坐标)),translation)。其中旋转是最复杂的一部分。

矩阵旋转
优点:
旋转轴可以是任意向量;
缺点:
旋转其实只需要知道一个向量+一个角度,一共4个值的信息,但矩阵法却使用了16个元素;
而且在做乘法操作时也会增加计算量,造成了空间和时间上的一些浪费;

欧拉旋转
优点:
很容易理解,形象直观;
表示更方便,只需要3个值(分别对应x、y、z轴的旋转角度);但按我的理解,它还是转换到了3个3*3的矩阵做变换,效率不如四元数;
缺点:
之前提到过这种方法是要按照一个固定的坐标轴的顺序旋转的,因此不同的顺序会造成不同的结果;
会造成万向节锁(Gimbal Lock)的现象。这种现象的发生就是由于上述固定坐标轴旋转顺序造成的。理论上,欧拉旋转可以靠这种顺序让一个物体指到任何一个想要的方向,但如果在旋转中不幸让某些坐标轴重合了就会发生万向节锁,这时就会丢失一个方向上的旋转能力,也就是说在这种状态下我们无论怎么旋转(当然还是要原先的顺序)都不可能得到某些想要的旋转效果,除非我们打破原先的旋转顺序或者同时旋转3个坐标轴。这里有个视频可以直观的理解下;
由于万向节锁的存在,欧拉旋转无法实现球面平滑插值;

四元数旋转
优点:
可以避免万向节锁现象;
只需要一个4维的四元数就可以执行绕任意过原点的向量的旋转,方便快捷,在某些实现下比旋转矩阵效率更高;
可以提供平滑插值;
缺点:
比欧拉旋转稍微复杂了一点点,因为多了一个维度;
理解更困难,不直观;

而在学习SQT数据结构之前,先学习一下四元数旋转。

四元数是对复数的扩充,它使用三个虚部i,j,k它们的关系如下:

i² = j² = k² = –1

四元数形式:

[w  v]或[ w   (x    y     z) ].

四元数定义了一个复数

w + xi + yj + zk

       四元数只能用来代替矩阵保存旋转信息,平移无法代替,旋转我们有 矩阵,欧拉角,四元数,

四元数是里面最复杂的一个但它可以在保证效率的同时减小矩阵1/4的内存占有量,同时又能避免欧拉角的万向锁问题,

无法用语言表达清楚万向锁的现象只有碰到过才能理解。。。


四元数和轴——角对:

设O为旋转角度,N为旋转轴(绕任意轴n旋转O度):

Q = [cos(O/2)  sin(O/2)N] = [ cos(O/2)     ( sin(O/2)Nx     sin(O/2)Ny      sin(O/2)Nz ) ]


负四元数:

-Q = –[w    (x y z)]  = [-w   (-x  -y  -z)] = –[w  v] = [-w -v]

    Q和-Q代表的是相同的角位移,如果我们将O加上360°的倍数,不会改变Q代表的角位移,但它使Q的四个分量都变负了。

因此,3D中的任意角位移都有两种不同的四元数表示方法,它们互为负数。


单位四元数:

几何上存在两个“单位”四元数,它们没有角位移, [1, 0]和[-1,0] 0代表0向量,让我们看看原因:

当O为360°的偶数倍时,有第一种形式,cos(O/2) = 1;

当O为360°的奇数倍时,有第二种形式,cos(0/2) =-1;

在这两种形势下都有sin(O/2) = 0,所以和旋转轴N是无关的,他的意义是,当旋转角O是360°的整数倍时,方位没有改变,并且旋转轴也是关紧要的.

注意:

       数学上只有一个单位四元数[1, 0],用四元数q乘以单位四元数[1,0],结果认识q。任意四元数q乘以另一个“几何单位”四元数[-1,0]时得到-q。几何上,因为q和-q代表的角位移相同,可

认为结果是相同。但在数学上,q和-q不相等,所以[-1,0]斌不是“真正”的单位四元数。


四元数的模:

公式:

    || q || = || [w (x y z)] || = √(w² + x² + y² + z²)

    所以

   || q || = √( cos²(O/2) + ( sin(O/2) ||n||)² )

   当n为单位向量时:

             = √( cos²(O/2) + sin²(O/2) * 1 )

    应用三角形公式 sin²(x) + cos²(x) = 1

             = √( cos²(O/2) + sin²(O/2) )

             = √1 = 1

如果为了用四元数来表示方位,我们仅仅使用符合这个规则的单位四元数。非单位四元数要查阅其他资料


四元数共轨和逆:

共轨:

四元数共轨记做 q*可以通过让四元数向量部分变负来获得:

q*  = [w v]* = [w -v]

    = [w (-x –y -z)]


逆:

用q^-1 表示逆

q^-1 = q* / || q ||

四元数乘以自己的逆等于“单位四元数”[1 0]

如果我们使用单位四元数是单位四元数那么就可以得到 q^-1 = q*. 所以单位四元数的共轨等于他的逆


四元数叉乘:


四元数乘法的标准定义:

[W1 V1] *[W2 V2]叉乘后还是四元数

(W1+X1i + Y1j + Z1k)(W2 + X2i + y2j + Z2K)

= [W1W2 - V1·V2  W1V2+W2V1+V2*V1]

叉乘满足结合律,但不满足交换律.

(a*b)*c = a*(b*c)

ab ≠ ba


叉乘的模:

||Q1 * Q2|| = ||Q1|| * ||Q2||

这个结论保证了两个单位四元数相乘还是单位四元数.


四元数逆的乘积:

(a*b)^1 = b^-1  * a^-1


四元数和点:

把一个标准3D点(x,y,z)扩展到四元数空间:P = [0, (x,y,z)]即可,一般情况下它不会是单位四元数

设Q为旋转四元数Q=[cos(O/2),nsin(O/2)],n为单位向量,O为旋转角度,那么P绕n旋转O度就是:

P` = Q * P * Q^-1

四元数的乘法和3D向量旋转的对应关系更多是理论上的,实际上,它几乎和把四元数转换成矩阵形式然后在用矩阵乘以向量时间是一样的.

多次旋转:

P` = B * (A * P * A^-1)B^-1

    = (B * A) * P * (A * B)^-1

这个形式是标准定义但我们不经常使用因为不好看,下面是经常使用的这个影响到了叉乘本身:

红色部分是改变后所影响的

[W1 V1] *[W2 V2]

(W1+X1i + Y1j + Z1k)(W2 + X2i + y2j + Z2K)

= [W1W2 - V1·V2 W1V2+W2V1+V2*V1]

相应的 四元数与3D向量的对应关系也随着改变:

P` = Q^-1 * P * Q

p` = B^-1 * (A^-1 * P * A) * B

     = (A * B)^-1 * P * (A * B)


四元数的差:

我们看:

A * D = B

两边都乘以 A^-1

A^-1 * A = A^-1 * B

因为 A^-1 * A = 1

所以 D = A^-1 * B

这就所谓的 “差”,被定义为一个方位到另一个方位的角位移,顺序是不能错的,从左向右.


四元数的点乘:

点乘那个很简单: Q1 · Q2 = [w1 v1] ·[w2 v2] = w1 · w2 + v1 · v2

点乘结是一个标量这个和向量点乘一样,对于单位四元数 a 和 b 有-1≤  a · b ≤1。

因为 a·b = –( a · –b),多以b和-b代表的角位移是一样的。

几何解释,四元数点乘a · b的绝对值越大,a 和 b代表的角位移越相似,这一点和 向量点乘类似.


四元数的对数,指数,标量乘运算:


对数:


指数:


标量相乘:

Kq = k[w v] = [kw kv]

从矩阵到欧拉角:

将角位移从矩阵形式转换到欧拉角需要考虑以下几点:

(1)必须清楚矩阵代表什么旋转:物体 -- 惯性还是 惯性 -- 物体,这里讨论使用惯性 -- 物体矩阵的技术,物体 -- 惯性矩阵转换成欧拉角的过程与之类似。

(2)对任意给定角位移,存在无穷多个欧拉角可以用来表示它。因为"别名"问题,这里讨论的技术总是返回"限制欧拉角",heading和bank的范围±180°,pitch的范围为±90°。

(3)矩阵可能是病态的,我们必须忍受浮点数精度的误差。有些矩阵还包括除旋转外的变换,如缩放、镜像等。这里只讨论工作在旋转矩阵上的变换。   

  //Listing 10.3: Extracting Euler angles from an inertial-to-object rotation matrix// Assume the matrix is stored in these variables:float m11,m12,m13;float m21,m22,m23;float m31,m32,m33;// We will compute the Euler angle values in radians and store them here:float h,p,b;// Extract pitch from m23, being careful for domain errors with asin(). We could have// values slightly out of range due to floating point arithmetic.float sp = –m23;if (sp <= –1.0f) {p = –1.570796f; // –pi/2} else if (sp >= 1.0) {p = 1.570796; // pi/2} else {p = asin(sp);}// Check for the Gimbal lock case, giving a slight tolerance// for numerical imprecisionif (sp > 0.9999f) {// We are looking straight up or down.// Slam bank to zero and just set headingb = 0.0f;h = atan2(–m31, m11);} else {// Compute heading from m13 and m33h = atan2(m13, m33);// Compute bank from m21 and m22b = atan2(m21, m22);}

从四元数到矩阵:

为了将角位移从四元数转换到矩阵形式,可以利用旋转矩阵,它能计算绕任意轴的旋转:

这个矩阵是用n和θ表示的,但四元数的分量是:

w = cos(θ/2)

x = nx sin(θ/2)

y = ny sin(θ/2)

z = nz sin(θ/2)

让我们看看能否将矩阵变形以代入w、x、y、z,矩阵的9个元素都必须这样做。幸运的是,这个矩阵的结构非常好,一旦解出对角线上的一个元素,其他元素就能用同样的方法求出。同样,非对角线元素之间也是彼此类似的。

考虑矩阵对角线上的元素,我们将完整地解出m11,m22和m33解法与之类似:

m11 = nx2(1 - cosθ) + cosθ

我们将从上式的变形开始,变形方法看起来像是在绕圈子,但你马上就能理解这样做的目的:

现在需要消去cosθ项,而代之以包含cosθ/2或sinθ/2的项,因为四元数的元素都是用它们表示的,像以前那样,设α=θ/2,先用α写出cos的倍角公式,再代入θ

// Listing 10.4: Converting a rotation matrix to a quaternion// Input matrix:float m11,m12,m13;float m21,m22,m23;float m31,m32,m33;// Output quaternionfloat w,x,y,z;// Determine which of w, x, y, or z has the largest absolute valuefloat fourWSquaredMinus1 = m11 + m22 + m33;float fourXSquaredMinus1 = m11 – m22 – m33;float fourYSquaredMinus1 = m22 – m11 – m33;float fourZSquaredMinus1 = m33 – m11 – m22;int biggestIndex = 0;float fourBiggestSquaredMinus1 = fourWSquaredMinus1;if (fourXSquaredMinus1 > fourBiggestSquaredMinus1) {fourBiggestSquaredMinus1 = fourXSquaredMinus1;biggestIndex = 1;}if (fourYSquaredMinus1 > fourBiggestSquaredMinus1) {fourBiggestSquaredMinus1 = fourYSquaredMinus1;biggestIndex = 2;}if (fourZSquaredMinus1 > fourBiggestSquaredMinus1) {fourBiggestSquaredMinus1 = fourZSquaredMinus1;biggestIndex = 3;}// Perform square root and divisionfloat biggestVal = sqrt(fourBiggestSquaredMinus1 + 1.0f) * 0.5f;float mult = 0.25f / biggestVal;// Apply table to compute quaternion valuesswitch (biggestIndex) {case 0:w = biggestVal;x = (m23 – m32) * mult;y = (m31 – m13) * mult;z = (m12 – m21) * mult;break;case 1:x = biggestVal;w = (m23 – m32) * mult;y = (m12 + m21) * mult;z = (m31 + m13) * mult;break;case 2:y = biggestVal;w = (m31 – m13) * mult;x = (m12 + m21) * mult;z = (m23 + m32) * mult;break;case 3:z = biggestVal;w = (m12 – m21) * mult;x = (m31 + m13) * mult;y = (m23 + m32) * mult;break;}  

从欧拉角到四元数:

为了将角位移从欧拉角转换到四元数,可以使用从欧拉角构造矩阵类似的方法。先将这三个旋转分别转换为四元数,这是一个简单的运算。再将这三个四元数连接成一个四元数。和矩阵一样,有两种情况需要考虑,第一种是惯性 -- 物体四元数,第二种是物体-- 惯性四元数。因为它们互为共轭关系,所以我们只推导惯性--物体四元数。

设欧拉角为变量h、p、b,设hpb分别绕轴y、x、z旋转的四元数。记住,使用负旋转量,因为它们指定坐标系中的旋转角度。

用正确的顺序连接它们得到公式10.24:

(记住,四元数乘法定义是按旋转的顺序从左向右乘。)

物体--惯性四元数是惯性--物体四元数的共轭,见公式10.25:

从四元数到欧拉角:

根据前面的公式发现:

  // Use global variables for input and outputfloat w,x,y,z;float h,p,b;// Extract sin(pitch)float sp = –2.0f * (y*z + w*x);// Check for Gimbal lock, giving slight tolerance for numerical imprecisionif (fabs(sp) > 0.9999f) {// Looking straight up or downp = 1.570796f * sp; // pi/2// Compute heading, slam bank to zeroh = atan2(–x*z – w*y, 0.5f – y*y – z*z);b = 0.0f;} else {// Compute anglesp = asin(sp);h = atan2(x*z – w*y, 0.5f – x*x – y*y);b = atan2(x*y – w*z, 0.5f – x*x – z*z);}// --惯性四元数转换到欧拉角,所用的代码和上面非常类似。只是将x、y、z值变负,因为物体--惯性四元数是惯性--物体四元数的共轭。//Listing 10.6: Converting an object-to-inertial quaternion to Euler angles// Extract sin(pitch)float sp = –2.0f * (y*z – w*x);// Check for Gimbal lock, giving slight tolerance for numerical imprecisionif (fabs(sp) > 0.9999f) {// Looking straight up or downp = 1.570796f * sp; // pi/2// Compute heading, slam bank to zeroh = atan2(–x*z + w*y, 0.5f – y*y – z*z);b = 0.0f;} else {// Compute anglesp = asin(sp);h = atan2(x*z + w*y, 0.5f – x*x – y*y);b = atan2(x*y + w*z, 0.5f – x*x – z*z);}

 

这篇关于Flag Engine(动画系统)学习笔记(四)——“骨骼姿势”前篇之四元数的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/193564

相关文章

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

不懂推荐算法也能设计推荐系统

本文以商业化应用推荐为例,告诉我们不懂推荐算法的产品,也能从产品侧出发, 设计出一款不错的推荐系统。 相信很多新手产品,看到算法二字,多是懵圈的。 什么排序算法、最短路径等都是相对传统的算法(注:传统是指科班出身的产品都会接触过)。但对于推荐算法,多数产品对着网上搜到的资源,都会无从下手。特别当某些推荐算法 和 “AI”扯上关系后,更是加大了理解的难度。 但,不了解推荐算法,就无法做推荐系

基于人工智能的图像分类系统

目录 引言项目背景环境准备 硬件要求软件安装与配置系统设计 系统架构关键技术代码示例 数据预处理模型训练模型预测应用场景结论 1. 引言 图像分类是计算机视觉中的一个重要任务,目标是自动识别图像中的对象类别。通过卷积神经网络(CNN)等深度学习技术,我们可以构建高效的图像分类系统,广泛应用于自动驾驶、医疗影像诊断、监控分析等领域。本文将介绍如何构建一个基于人工智能的图像分类系统,包括环境

水位雨量在线监测系统概述及应用介绍

在当今社会,随着科技的飞速发展,各种智能监测系统已成为保障公共安全、促进资源管理和环境保护的重要工具。其中,水位雨量在线监测系统作为自然灾害预警、水资源管理及水利工程运行的关键技术,其重要性不言而喻。 一、水位雨量在线监测系统的基本原理 水位雨量在线监测系统主要由数据采集单元、数据传输网络、数据处理中心及用户终端四大部分构成,形成了一个完整的闭环系统。 数据采集单元:这是系统的“眼睛”,

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;

嵌入式QT开发:构建高效智能的嵌入式系统

摘要: 本文深入探讨了嵌入式 QT 相关的各个方面。从 QT 框架的基础架构和核心概念出发,详细阐述了其在嵌入式环境中的优势与特点。文中分析了嵌入式 QT 的开发环境搭建过程,包括交叉编译工具链的配置等关键步骤。进一步探讨了嵌入式 QT 的界面设计与开发,涵盖了从基本控件的使用到复杂界面布局的构建。同时也深入研究了信号与槽机制在嵌入式系统中的应用,以及嵌入式 QT 与硬件设备的交互,包括输入输出设

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]