当前位置: 首页 > ops >正文

Unity里的对象旋转数值跳转问题的原理与解决方案

文章目录

  • 1. 问题描述
  • 2. 问题原因
  • 3. 解决方案
  • 3.1通过多个父子关系从而控制旋转(推荐)
  • 3.2 使用四元数进行旋转

1. 问题描述

我们现在写一个3D的Unity程序,我们现在设置了一个物体后,我们想旋转使其改为我们想要的情况。但是我们如果rotation输入了3个值后,我们发现现在旋转的时候,rotation的值会突然跳转变换到另一个值。这个时候我们修改例如x的值,y和z值也会随着x值发生变化。我们在这种情况下难以通过不断调整三个坐标轴的旋转将我们的物体旋转到我们想要的情况。
在这里插入图片描述
在这里插入图片描述

2. 问题原因

了解图形学的话,我们知道旋转(Rotation)是变换(Transformation)的一种,其底层计算使用矩阵来表示。
我们一般使用homogeneous co0ordinates(齐次坐标)来进行计算。
在三维空间中,绕z轴的旋转可以看作是在所有z坐标相同的平面上进行的二维旋转。
因此关于z轴旋转的情况如下:
在这里插入图片描述
关于y轴和x轴旋转的情况如下:
在这里插入图片描述
由于是矩阵计算,矩阵乘法有结合律但是没法使用交换律。
因此当我们完成了旋转之后,我们再次更改值,旋转顺序就被我们打乱了,因此矩阵的值会突然发生变化,此时我们再修改值,也不会是我们想象中的只变化一个轴的值,另外的值也会发生变化。

3. 解决方案

3.1通过多个父子关系从而控制旋转(推荐)

在这里插入图片描述

在 Unity中,旋转的顺序是先绕 Z 轴旋转,然后绕 X 轴旋转,最后绕 Y 轴旋转。也就是说,对于欧拉角 (30, 40, 50),旋转顺序如下:

  1. 先绕 Z 轴旋转 50°。
  2. 再绕 X 轴旋转 30°。
  3. 最后绕 Y 轴旋转 40°。

因此我们可以分别使用三个父子关系从而分别控制不同的轴进行旋转。
但是这里我们并不是Z轴在最外面作为父物体,而是Y轴在最外面作为父物体。
因为在 Unity 中使用父子关系来控制旋转时,每个子物体的旋转是相对于其父物体的局部坐标系进行的。在 Unity 中直接设置一个物体的欧拉角旋转时,这个旋转是相对于世界坐标轴的。
换句话说在Unity中根据自身坐标系旋转的顺序是Y-X-Z,根据世界坐标系旋转的顺序是Z-X-Y。所以这里正确的父子关系如图所示,顺序为Y-X-Z。
在这里插入图片描述
这里使用CubeYRotation控制Y轴的旋转。
在这里插入图片描述
接着用其子物体CubeXRotation控制X轴的旋转。
在这里插入图片描述
最后使用其子物体CubeZRotation控制Z轴的旋转。
在这里插入图片描述
将其分别设置为和原来的Cube一样的旋转值,通过这样的方式我们可以得到和原来的Cube一样的效果,而且,这时候我们再分别旋转这些对象的Rotation可以只修改一个轴的Rotation,不会产生一次旋转多个值变化的情况。

这种方法易于控制,并且使用我们日常使用的欧拉角,所以方便理解,现实实践的时候可以不按照这个顺序进行控制,用这种父子关系控制旋转即可。
我们在实际使用Unity中也可以多使用父子关系控制对象的变换(包含位置、旋转、缩放),通过父子关系我们可以更好控制对象的位置关系和实际效果,还可以帮助我们更好管理对象的层级结构。
如图所示,我将这个场景里的所有对象放在了一个大的父物体下,方便控制。
在这里插入图片描述

为了验证前面我们的结论我们可以试验下面的几个代码。
第一个代码:

transform.Rotate(45, 45, 45);

第二个代码:

transform.Rotate(0, 0, 45, Space.World);
transform.Rotate(45, 0, 0, Space.World);
transform.Rotate(0, 45, 0, Space.World);

第三个代码:

transform.Rotate(0, 45, 0);
transform.Rotate(45, 0, 0);
transform.Rotate(0, 0, 45);

这三个代码的效果一样,也能说明在Unity中根据自身坐标系旋转的顺序是Y-X-Z,根据世界坐标系旋转的顺序是Z-X-Y。

3.2 使用四元数进行旋转

如果我们学习Unity的教程,一般会告诉你旋转Unity采取四元数来表示和计算旋转,因为四元数不会像欧拉角一样存在万向锁(万向锁是使用欧拉角表示旋转时可能遇到的一个问题,即当旋转到某些特定角度时,会失去一个维度的自由度,导致旋转变得不稳定。)和表达方式多样的问题(欧拉角有无数种表达方式,这可能导致在计算或存储时出现混淆或错误)。
但是它并没有欧拉角那样易于理解,这里只稍微说下简单的概念。
它是一种扩展了复数的概念,可以表示为一个实部和三个虚部的组合,通常表示为 q=w+xi+yj+zkq=w+xi+yj+zkq=w+xi+yj+zk,其中w,x,y,zw,x,y,zw,x,y,z是实数,而i,j,ki,j,ki,j,k是虚数单位。这里实部与旋转的余弦值有关,虚部与旋转轴的方向向量有关。
四元数可以表示为:q=cos(θ/2)+(u⋅i)sin(θ/2)q=cos(θ/2)+( u ⋅ i )sin(θ/2)q=cos(θ/2)+(ui)sin(θ/2)其中,θθθ是旋转角度, uuu是旋转轴的单位向量。

我们这里使用四元数进行旋转,这是Unity比较推荐的方式。
我们先创建三个旋转四元数,分别对应 X、Y、Z 轴的旋转角度。然后将这三个四元数相乘,得到最终的旋转四元数。将这里的最终四元数赋给物体的rotation从而完成旋转。

Quaternion rotationX = Quaternion.Euler(30f, 0f, 0f);
Quaternion rotationY = Quaternion.Euler(0f, 40f, 0f);
Quaternion rotationZ = Quaternion.Euler(0f, 0f, 50f);
Quaternion finalRotation = rotationZ * rotationY * rotationX;transform.rotation = finalRotation;

这个方式相较于前者在Inspector里修改不够直观方便,因此更推荐前者。

http://www.xdnf.cn/news/17121.html

相关文章:

  • Spring Boot集成方案 + Elasticsearch向量检索,语义搜索核弹
  • Linux seLinux
  • AI大语言模型如何重塑软件开发与测试流程
  • 3D开发引擎HOOPS赋能AEC领域:可视化技术助力建筑数字化转型!
  • Promise
  • 【JS-7-ajax】AJAX技术:现代Web开发的异步通信核心
  • Python包管理新利器:uv全面解析与Conda对比指南
  • 一文读懂:什么是CLIP
  • Redis集群核心原理与实战解析
  • C语言的数组与字符串练习题2
  • 【前端开发】四. JS内置函数
  • 5G毫米波射频前端测试:OTA暗室与波束成形性能验证
  • RuoYi-Cloud 微服务本地部署详细流程实录(IDEA + 本地 Windows 环境)
  • 商派小程序商城(小程序/官网/APP···)的范式跃迁与增长再想象
  • 参考线程池构建一个高性能、配置驱动的Docker容器池
  • 基于Simulink/MWORKS的文字与开关量混合传输系统设计
  • [LVGL] 部件lv_obj | 样式lv_style | LV_PART_ | LV_STATE_
  • Cartographer安装测试与模块开发(四)--Cartographer纯定位思路
  • Linux基本指令:掌握系统操作的钥匙
  • 浅谈RNN被Transformer 取代的必然性
  • 面试题:基础的sql命令
  • 在LLM小型化趋势下,AI Infra需要做出哪些相应调整?
  • 【完整源码+数据集+部署教程】爬行动物异常检测系统源码和数据集:改进yolo11-GhostDynamicConv
  • JavaScript 中 var、let 和 const 的区别与使用场景
  • TCP的三次握手和四次挥手实现过程。以及为什么需要三次握手?四次挥手?
  • [GESP202309 四级] 2023年9月GESP C++四级上机题题解,附带讲解视频!
  • Python爬虫08_Requests聚焦批量爬取图片
  • layernorm backward CUDA优化分析
  • linux nfs+autofs
  • mq_unlink系统调用及示例