万向节死锁产生的根本原因是,旋转矩阵是依次进行的,假设先围绕x轴旋转,再围绕y轴旋转,最后围绕z轴旋转,这就导致物体其实是围绕自己的X轴旋转,而不是世界坐标的X轴旋转。

表现就是,在一个欧拉角(x,y,z)下,改变x的值,物体会围绕物体自己的x轴进行旋转,而不是世界坐标系的x轴进行旋转。

下图所示,改变x值,都是在绕自己的红色的轴(x轴)转。RGB三个颜色分别对应XYZ正半轴:

首先,旋转3D模型时,实际是对原始模型的顶点进行旋转。比如旋转(x1,y1,z1),就是把原始模型旋转到这个角度,然后渲染显示。当旋转变成(x2,y2,z2),会把原始模型旋转到这个角度,然后渲染显示。

然后,进行一次旋转时,物体是先围绕x轴进行旋转,这时候物体的局部坐标系和世界坐标系是重合的,虽然是围绕世界坐标的x轴旋转,但也是围绕自己的x轴进行旋转。最后得到的旋转结果,也变成了物体是绕自己的x轴转的结果了。

最后,当把物体的x轴旋转到与世界的z轴重合时,欧垃角的x和z旋转结果就都一样了,也就丢失了一个维度。另一方面,比如在(30, 30, 30)的欧垃角下,把y从30调到60会发现并不是绕自己的y轴在转,也不是绕世界坐标的y旋转。

可以自己通过欧拉角计算出顶点旋转后的坐标来验证这个。

参考资料:

附上自己的Unity测试代码:

using UnityEngine;

[ExecuteInEditMode]

public class TestEuler : MonoBehaviour

{

public Vector3 Euler;

public Vector3 OrgPosOfA;

public Vector3 OrgPosOfB;

public Vector3 OrgPosOfC;

public Transform TransA;

public Transform TransB;

public Transform TransC;

// Use this for initialization

void Start()

{

}

// Update is called once per frame

void Update ()

{

TransA.position = Rotate(OrgPosOfA, Euler) + transform.position;

TransB.position = Rotate(OrgPosOfB, Euler) + transform.position;

TransC.position = Rotate(OrgPosOfC, Euler) + transform.position;

}

Vector3 Rotate(Vector3 pos, Vector3 euler)

{

pos = RotateX(pos, euler.x * Mathf.Deg2Rad);

pos = RotateY(pos, euler.y * Mathf.Deg2Rad);

pos = RotateZ(pos, euler.z * Mathf.Deg2Rad);

return pos;

}

Vector3 RotateX(Vector3 pos, float r)

{

Vector3 newPos = pos;

float cos = Mathf.Cos(r);

float sin = Mathf.Sin(r);

newPos.y = pos.y * cos + pos.z * sin;

newPos.z = -pos.y * sin + pos.z * cos;

return newPos;

}

Vector3 RotateY(Vector3 pos, float r)

{

Vector3 newPos = pos;

float cos = Mathf.Cos(r);

float sin = Mathf.Sin(r);

newPos.x = pos.x * cos - pos.z * sin;

newPos.z = pos.x * sin + pos.z * cos;

return newPos;

}

Vector3 RotateZ(Vector3 pos, float r)

{

Vector3 newPos = pos;

float cos = Mathf.Cos(r);

float sin = Mathf.Sin(r);

newPos.x = pos.x * cos + pos.y * sin;

newPos.y = -pos.x * sin + pos.y * cos;

return newPos;

}

void OnDrawGizmos()

{

//坐标轴

Gizmos.color = Color.red;

Gizmos.DrawLine(transform.position, transform.position + Vector3.right);

Gizmos.color = Color.green;

Gizmos.DrawLine(transform.position, transform.position + Vector3.up);

Gizmos.color = Color.blue;

Gizmos.DrawLine(transform.position, transform.position + Vector3.forward);

//旋转后的点

Gizmos.color = Color.red;

Gizmos.DrawLine(transform.position, TransA.position);

Gizmos.color = Color.green;

Gizmos.DrawLine(transform.position, TransB.position);

Gizmos.color = Color.blue;

Gizmos.DrawLine(transform.position, TransC.position);

}

}

下图所示,改变x值,都是在绕红色的轴(x轴)转。RGB三个颜色分别对应XYZ正半轴:

万向节死锁_万向节死锁产生的原因相关推荐

  1. 万向节死锁_万向节死锁 gimbal lock

    ,如下图一,把灰色箭头想象成是一架飞机,红,绿蓝三个圈看作是三个外围控制器,外圈带动所有里圈运动,里圈的运动不影响外圈. 1,首先,绕Y轴旋转(旋转绿圈),来确定前进的方向.这时红圈与蓝圈都跟着旋转. ...

  2. 连续锁定2个不同的锁会死锁_研究死锁–第5部分:使用显式锁定

    连续锁定2个不同的锁会死锁 在我的上一个博客中,我研究了使用Java的传统synchronized关键字和锁排序来修复破碎的,死锁的余额转移示例代码. 但是,有另一种方法称为显式锁定. 在这里,将锁定 ...

  3. oracle 行级死锁_解决Oracle数据库死锁

    介绍 本文我们尝试总结在多个用户并发情况下,如何识别和解决删除操作期间发生的死锁问题,在开始之前,我们先简单描述一下什么是死锁以及什么东西会导致死锁. 死锁 在任何数据库中发生死锁都是不愉快的,即使是 ...

  4. lua mysql 死锁_使用 mysqladmin debug 查看死锁信息

    使用 mysqladmin debug 查看死锁信息 mysqladmin -S /mysql/data/mysql.sock debug 然后在error日志中,会看到: 11 lock struc ...

  5. java解决线程死锁_为你解决Java线程死锁

    产生死锁的原因: 1. 系统资源不足.分配不当.系统中都会有一种不可剥夺的资源,若是这些资源不能够满足进程运行的需要,那么就只能进行资源争夺,从而陷入死锁. 注意:只有对不可剥夺资源的竞争才可能产生死 ...

  6. 什么是死锁,产生死锁的原因及必要条件

    什么是死锁? 所谓死锁,是指多个进程在运行过程中因争夺资源而造成的一种僵局,当进程处于这种僵持状态时,若无外力作用,它们都将无法再向前推进. 因此我们举个例子来描述,如果此时有一个线程A,按照先锁a再 ...

  7. 死锁面试题(什么是死锁,产生死锁的原因及必要条件)

    什么是死锁? 所谓死锁,是指多个进程在运行过程中因争夺资源而造成的一种僵局,当进程处于这种僵持状态时,若无外力作用,它们都将无法再向前推进. 因此我们举个例子来描述,如果此时有一个线程A,按照先锁a再 ...

  8. 【操作系统】什么是死锁,以及死锁产生的原因和必要条件

    一.什么是死锁? 所谓死锁,就是在两个或多个并发进程中,如果每个进程持有某种资源而又都等待着别的进程释放它或它们现在保持着的资源,否则就不能向前推进,此时每个进程都占用了一定的资源但又都不能向前推进, ...

  9. python中threading产生死锁_什么是死锁,如何避免死锁(4种方法)

    当两个线程相互等待对方释放资源时,就会发生死锁.Python 解释器没有监测,也不会主动采取措施来处理死锁情况,所以在进行多线程编程时应该采取措施避免出现死锁. 一旦出现死锁,整个程序既不会发生任何异 ...

最新文章

  1. 小人脸检测 - Finding Tiny Faces
  2. 图像放大算法一:最近邻法(Nearest Interpolation)
  3. 【前沿技术】“中国天眼”观测到宇宙极端爆炸起源证据
  4. ServiceStack.Text反序列化lowercase_underscore_names格式的JSON
  5. mysql读取和写入的峰值_计算MySQL的内存峰值公式
  6. C#趣味程序---真分数序列
  7. 由浅入深CIL系列:5.抛砖引玉:判断string是否为空的四种方法的CIL代码看看效率如何?...
  8. e记法 python 底数_备战python二级
  9. 转:复杂网络分析总结
  10. 凝结11年技术实力 弹性计算国内首著发布
  11. idea打包 jar文件
  12. 卡西欧科学计算机使用方法,科学计算器的使用方法
  13. 王者荣耀以鸿蒙起网名,王者荣耀
  14. 做数据分析的36款常用工具!!!初学者必备,纯干货!!
  15. Rest——分布式超媒体系统的架构风格
  16. cent7虚拟机镜像_centos7.3系统下载
  17. 宝马计划明年推出智能助手,将其添加到车辆中
  18. 《老板最爱的简历表》阅读
  19. 无法连接上 127.0.0.1:XXXX (127.0.0.1)。 - connect (111: 拒绝连接)
  20. Lync(Skype)接口开发实录

热门文章

  1. java ssi_快速部署SSI框架
  2. gm220s路由器怎么设置_二级路由器怎么设置_二级路由器设置图解教程-192路由网...
  3. 监控视频压缩存储该如何解决?
  4. 破解JS加密:url unicode加密而已
  5. 笔试逻辑智力题找规律题总结4
  6. 展望:可见光通信技术标准体系建设
  7. 李开复写给中国大学生的第三封信
  8. python刷弹幕_每个大主播都是满屏弹幕,怎么做到的?Python实战无限刷弹幕!
  9. php 判断爬虫程序,php判断搜索引擎蜘蛛爬虫还是人为访问代码
  10. 安全大数据的7个V——大数据基础问题与信息安全的交叉探究