首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >四元数到达万向节锁

四元数到达万向节锁
EN

Stack Overflow用户
提问于 2015-02-27 16:52:13
回答 2查看 8.1K关注 0票数 12

为了避免旋转时的角度锁定,我尝试切换到四元数。不知怎么的,我还在设法找到万向节锁。

我不确定是由于我实现的数学,还是设计错误,所以请指出我是否应该改变我的对象坐标的方法。

我的每个对象都持有一个X,Y,Z值,以及一个俯仰,偏航,滚动值。当我更改旋转值时,对象将根据上述信息重新计算其顶点。这一逻辑如下:

代码语言:javascript
运行
AI代码解释
复制
    // vertex array
    vertices[x] -= /*Offset by origin point*/;

    // Quat.'s representing rotation around xyz axes
    Quaternion q1 = Quaternion(glm::vec3(1,0,0),pitch);
    Quaternion q2 = Quaternion(glm::vec3(0,1,0),yaw); 
    Quaternion q3 = Quaternion(glm::vec3(0,0,1),roll); 

    // total rotation
    Quaternion TotalRot = ( (q3 * q2) * (q1) ); 

    // conversion of original coordinates to quaternion
    Quaternion Point1 = Quaternion(0, vertices[x].x(), vertices[x].y(), vertices[x].z()); 

    // resulting rotated point
    Quaternion Point2 = Quaternion( (TotalRot * Point1) * TotalRot.inverse() );

    // placing new point back into vertices array
    vertices[x] = QVector3D(round(Point2.v.x),round(Point2.v.y),round(Point2.v.z));
    vertices[x]+= /*Undo origin point offset*/;

"vertices[]“是对象顶点数组。上面注释掉的原点偏移量只是为了使对象围绕适当的原点旋转,因此相对于0,0,0,0,0,0,0,0,0,因为旋转发生在该点附近(对吗?)

我对我的问题有一个形象的描述,我首先偏航90度,俯仰45度,然后-90滚动,但滚动轴变得平行于俯仰轴:

编辑:

我试着把这3轴四元数相乘,然后乘以4x4矩阵,然后乘以顶点点,但我仍然把万向节锁/到达奇点相乘!

代码语言:javascript
运行
AI代码解释
复制
    Quaternion q1 = (1,0,0,pitch);
    Quaternion q2 = (0,1,0,yaw);
    Quaternion q3 = (0,0,1,roll);
    Quaternion qtot = (q1*q2)*q3;
    Quaternion p1(0, vertices[x].x(), vertices[x].y(), vertices[x].z());
    QMatrix4x4 m;
    m.rotate(qtot);
    QVector4D v = m*p1;
    vertices[x] = QVector3D(v.x(),v.y(),v.z());
EN

回答 2

Stack Overflow用户

发布于 2015-06-21 09:17:51

您的问题是,即使使用四元数,您仍然存储三个螺距、偏航和滚动值,而不是四元数,以表示对象的方向。

下面是使用四元数进行旋转的方法:

  1. 不是存储每个对象的X、Y、Z、螺距、偏航、滚动,而是在每个对象中存储X、Y、Z、orientation,其中orientation是从初始值(0、0、0、1)开始的四元数,意思是没有旋转。存储每个对象的俯仰、偏航和滚动容易受到奇点(万向节锁)的影响,因为当添加小的变化时,中间的一个旋转(例如,一个螺距)可能导致该对象平行于一个旋转轴(例如,偏航轴),因此围绕该轴的下一个旋转可能失败。
  2. 然后,当对象被旋转时,确定在该帧中发生的对象的音调、偏航和滚动(假设您的输入设备以该形式提供旋转),将其转换为四元数,然后将该四元数预乘为对象的orientation四元数。这种方法不太容易受到奇点的影响,因为预计每一帧的旋转变化都很小。
  3. 更改方向后,不要直接修改对象的X、Y和Z( verticies数组)。相反,当对象的方向发生变化时,创建一个新的旋转矩阵作为对象的世界转换矩阵的一部分(以及缩放和平移;要获得最佳结果,请将世界转换计算为translation * rotation * scaling)。
  4. 每隔几个帧,您就应该对orientation四元数进行规范化,以避免由于舍入错误而导致的方向上的不适当的更改。
票数 12
EN

Stack Overflow用户

发布于 2015-02-27 17:28:44

如果你用一个欧拉角表示并把它转换成四元数,仅仅是为了做向量旋转,那么你仍然只是使用欧拉角。只要你在任何地方都有欧拉角,万向节锁定问题就会继续存在。你需要完全切换到四元数,如果你想要完全消除这个问题的话,永远不要在任何地方进行欧拉角表示。

这样做的基本方法是,您可以在计算的远端使用Euler角(作为原始输入或最终输出),如果这对您更方便的话(例如,Euler角通常是一种“人类可读性”的表示)。但是,将四元数用于其他一切(您可以偶尔将其转换为旋转矩阵,因为它们对于旋转向量更有效),并且从不对任何“坏”的旋转表示(欧拉角、轴角等)进行中间转换。“万向无锁”的四元数和旋转矩阵的好处,只有当你坚持这两个表示在你的所有计算。

因此,一方面,您有奇异表示( "gimbal锁“的正式术语是奇点):

  • 欧拉角(顺便说一句,有12种);以及
  • 轴角

在另一边,你有一个没有奇异性的表示:

  • 四元数(更有效的内存和组合运算);以及
  • 旋转矩阵(更有效地将旋转应用于向量)。

每当您使用奇异表示操作(比如将几个旋转集合在一起,或移动一个旋转对象)时,您将不得不在每次计算中都担心这种奇异性。当你用奇点无关表示做同样的操作时,你就不用担心这个问题了(但是你必须担心约束,这是四元数的单位范数约束,旋转矩阵的适当正交性)。当然,任何时候,当你转换到或从一个奇异表示,你必须担心奇点。这就是为什么你只应该在你的计算的远端进行转换(当你进入或离开时),并且在你的计算中坚持使用非奇异表示。

欧拉角的唯一好用途是为了人类的可读性,周期。

票数 8
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/28776788

复制
相关文章
字符,字符集,字符编码
现在Unicode已然一统天下,我想很多年轻的程序员可能都没遇到过编码问题,更不用说了解编码的发展了。前些日子在一个老网站上偶遇乱码,虽然入行时间不短,但对其究竟也是不甚了解,好奇心驱使下落入深坑。还好经过一段时间的摸爬滚打,边学边写,总算大概理清了个脉络,记录之,分享之。
_春华秋实
2019/02/22
1.6K0
字符,字符集,字符编码
linux中计算行数,字数,字符数的10个wc命令示例
wc命令的功能为统计指定文件中的字节数、字数、行数, 并将统计结果显示输出。 # wc [options] filenames 以下是该命令提供的选项和用法。 -c, --bytes 输出目标文件中字节的计数结果 -m, --chars 输出目标文件的中字符的计数结果 -l, --lines 输出目标文件中 行 的计数结果 --files0-from=F 从NUL-terminated指明的名字在文件F中的文件中读取,如
入门笔记
2022/06/02
9270
[每日一题]字符数组
前面的题基本都是数组里面存数字,相信大家也基本练习的差不多了,今天给大家推荐的一题呢,比较简单,但可以算是数组存字符的一个开始吧!懂的同学可以忽略! 题目描述 有一字符串,包含n个字符。写一函数,将此字符串中从第m个字符开始的全部字符复制成为另一个字符串。 输入 数字n 一行字符串 数字m 输出 从m开始的子串 样例输入 6 abcdef 3 样例输出 cdef PS:详细题解见C语言网1048题 另外,有兴趣的同学还可以加入C语言网官方微信群,一起讨论C语言 有找密码或者其他问题也可以到里面找相关人员解
编程范 源代码公司
2018/04/18
8980
字符数组
char message[5] = {'H', 'e', 'l', 'l', 'o'};
pigeon
2022/04/11
4600
字符数组
字符集和字符编码
我们都知道在计算机内部,所有的数据在存储和运算的时候都应该使用二进制进行表示。例如字母,数字等等。通过二进制进行表示,我们可以指定很多规则来表示这些字符,为了避免不一致性,美国国家标准学会(American National Standard Institute , ANSI )制定了 ASCII(American Standard Code for Information Interchange,美国信息交换标准代码)编码。
用户7657330
2020/08/14
1.1K0
字符数组反转_字符数组的初始化
关于字符串的反转,倒是很简单,但是编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 char[] 的形式给出。
全栈程序员站长
2022/08/18
1.2K0
字符集
本文主要讲解字符集和字符编码的一些概念,通常我们所说的字符集其实指的包含了字符编码集+字符编码。但字符集有时候有时候又只是字符编码集的简称,具体语义根据上下文判断理解就行,也不是必须分的很清楚。
@阿诚
2020/09/01
1.8K0
字符集
字符集与字符编码总结
转载请注明出处。请前往 Tiga on Tech 查看原文以及更多有趣的技术文章。
Tiga
2020/01/23
1.2K0
字符集与字符编码总结
6.3 字符数组
1、对字符数组初始化,最容易理解的方式是用“初始化列表”,把各个字符依次赋给数组中各元素。
小林C语言
2019/07/12
6530
5.3 字符数组
注意:用“”%s”格式符输入输出字符串时,printf函数中的输出项是字符数组名而不是数组元 素名
小林C语言
2019/08/19
5600
ASP数组排序_字符数组
<% ‘===================================== ‘作者:80端口,阿里西西 ‘时间:2005-12-23 ‘作用:对数据进行重新排序 ‘===================================== Function NewOrder(sz) Dim ali,icount,i,ii,j,itemp ali=split(sz,”,”) icount=UBound(ali) For i=0 To icount For j=icount – 1 To i Step -1 If j+1 <= UBound(ali) Then If int(ali(j))<int(ali(j+1)) Then itemp=ali(j) ali(j)=ali(j+1) ali(j+1)=itemp End If End If Next Next For ii=0 to Ubound(ali) If ii = Ubound(ali) Then NewOrder = NewOrder & ali(ii) Else NewOrder = NewOrder & ali(ii) & “,” End If Next End Function %>
全栈程序员站长
2022/11/01
3.4K0
去除字符数组中指定的字符
比较实用的小程序,备份记录。 //去除字符串中指定字符 static void Delete_Char(char str[],char target) {         uint8_t i,j;         for(i=j=0;str[i]!='\0';i++)         {             if(str[i]!=target)             {                 str[j++]=str[i];             }         }         s
Winter_world
2020/09/25
1.5K0
C语言数组——字符数组
字符数组顾名思义就是数组的元素类型为字符型的数组。特殊之处在于它是数组元素为字符的数组。其定义的一般形式和注意事项与之前讲解的一般数组类似,只是其中的类型说明符是char。当然,并不是说类型说明符只能是char,也可以是long、int等,但是由于char型只占用一个字节的大小,使用long型和int型来定义字符数组会造成资源的浪费,因此一般选择使用char型来定义字符数组。
C语言中文社区
2022/05/30
7.6K0
C语言数组——字符数组
29:统计字符数
29:统计字符数 总时间限制: 1000ms 内存限制: 65536kB描述 给定一个由a-z这26个字符组成的字符串,统计其中哪个字符出现的次数最多。 输入输入包含一行,一个字符串,长度不超过1000。输出输出一行,包括出现次数最多的字符和该字符出现的次数,中间以一个空格分开。如果有多个字符出现的次数相同且最多,那么输出ascii码最小的那一个字符。样例输入 abbccc 样例输出 c 3 来源1744 1 #include<iostream> 2 #include<cstdio
attack
2018/04/03
1K0
C语言数组——字符数组
C/C++学习资源(百度云盘链接) 计算机二级资料(过级专用) C语言学习路线(从入门到实战) 编写C语言程序的7个步骤和编程机制 C语言基础-第一个C程序 C语言基础-简单程序分析 VS2019编写简单的C程序示例 简单示例,VS2019调试C语言程序 C语言基础-基本算法 C语言基础-数据类型 C语言中的输入输出函数 C语言流程控制语句 C语言数组——一维数组 C语言数组——二维数组
全栈程序员站长
2022/09/08
6.2K0
C语言数组——字符数组
字符集和字符编码(Charset & Encoding)
计算机中储存的信息都是用二进制数表示的;而我们在屏幕上看到的英文、汉字等字符是二进制数转换之后的结果。通俗的说,按照何种规则将字符存储在计算机中,如’a’用什么表示,称为”编码”;反之,将存储在计算机中的二进制数解析显示出来,称为”解码”,如同密码学中的加密和解密。在解码过程中,如果使用了错误的解码规则,则导致’a’解析成’b’或者乱码。
空空云
2018/09/27
1.9K0
字符集和字符编码(Charset & Encoding)
java字符集
1、JVM中单个字符占用的字节长度跟编码方式有关,而默认编码方式又跟平台是一一对应的或说平台决定了默认字符编码方式;
西门呀在吹雪
2020/11/09
2.2K0
MySQL 字符集
MySQL 支持多种字符集,使您能够使用各种字符集存储数据,并根据给定排序规则执行比较。
恋喵大鲤鱼
2023/10/12
3390
理清字符集和字符编码关系
计算机内部由集成电路(Integrated Circuit,IC)构成,IC的所有引脚,只有直流电压0V和5V两个状态。也就是说,IC的一个引脚,只能表示两个状态。正是由于这个原因,决定了计算机的信息只能用二进制数处理。
木可大大
2018/04/10
1.7K7
理清字符集和字符编码关系
C++字符数组存放字符串 | 字符指针变量
C++指向数组的指针作函数参数  一维数组名可以作为函数参数传递,多维数组名也 可作函数参数传递。  C++用字符数组存放一个字符串 在C++中可以用多种方法访问一个字符串,第一种字符数组: #include<iostream>//预处理 using namespace std;//命名空间  int main()//主函数  {   char str[]="关注:C语言入门到精通";   cout<<str<<endl;    return 0; //函数返回值为0; } 编译运行结果: 关注:C语言入
小林C语言
2020/12/18
1.3K0
C++字符数组存放字符串 | 字符指针变量

相似问题

在字符数组程序集X86 embedded中获取索引位置的字符

20

字符串搜索,x86程序集

12

程序集x86逐字符读取字符串。

12

移动字符数组的值以注册x86内联程序集

20

如何在C中计算字符数组中输入的字符数

11
添加站长 进交流群

领取专属 10元无门槛券

AI混元助手 在线答疑

扫码加入开发者社群
关注 腾讯云开发者公众号

洞察 腾讯核心技术

剖析业界实践案例

扫码关注腾讯云开发者公众号
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文