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

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.dtcms.com/a/318237.html

相关文章:

  • GaussDB 数据库架构师修炼(六)-2 集群工具管理-重建备库
  • 17.10 智谱AI GLM 篇:ChatGLM3-6B 快速上手
  • 【教程】C++编译官方CEF3
  • ORA-10458: standby database requires recovery
  • C++ Eigen最小二乘拟合三维直线
  • KMP-next数组详解
  • sigaction结构体详解
  • 推荐一款优质的开源博客与内容管理系统
  • 集团敏捷组织转型项目研讨材料(105页PPT)精品
  • Mac安装WebStorm for Mac v2025.1.1
  • PDF注释的加载和保存的实现
  • Enhancing Long Video Question Answering with Scene-Localized Frame Grouping
  • python中的推导式
  • Android PDFBox 的使用指南
  • 力扣热题100------136.只出现一次的数字
  • 【纵火犯的春天】纵火犯是如何解题leetcode的?
  • Python驱动的无人机多光谱-点云融合技术在生态三维建模与碳储量/生物量/LULC估算中的全流程实战
  • JDK9+ Method.class.getDeclaredFields() Method实例将不能再直接通过反射修改
  • 无人机航拍数据集|第4期 无人机太阳光伏板红外目标检测YOLO数据集10945张yolov11/yolov8/yolov5可训练
  • 大疆无人机使用eport连接Jetson主板实现目标检测
  • selenium操作指南
  • 前端路由守卫
  • JavaWeb服务器/servlet容器(Tomcat、Undertow 、WebLogic)
  • 前端应用场景题目(待总结优化)
  • 攻防世界WEB(新手模式)20-unseping
  • 基于 kubeadm 搭建 k8s 集群
  • 京东商品评论接口开发全指南:从数据获取到分析应用实战
  • 【20205CVPR-目标检测方向】基于事件的高效目标检测:具有空间和时间注意力的混合神经网络
  • Lodash 的终极进化Radashi
  • JAVA 程序员cursor 和idea 结合编程