[Unity] Unity 3D 中的旋转

2023-11-11

Unity 3D 中的旋转

一、Unity 3D 中 Rotation

在Unity中,旋转通常可以用一个三维向量(x,y,z)表示。实际上这是欧拉角。三个分量分别是绕x轴、y轴和z轴的旋转角度。

要对一个GameObject进行旋转,可以直接通过如下代码:

transform.Rotate(xAngle, yAngle, zAngle);

那么有如下疑问:

  1. 上述的x轴、y轴、z轴指的是哪组基?是世界坐标系下的xyz轴,还是局部坐标系下的xyz轴?还是其他?
  2. 旋转的正方向如何?
  3. 旋转的顺序如何?

下面一一解答。

二、旋转轴

首先,回答第一个问题,到底旋转轴是哪个坐标系的基?分为如下三种情况。

1. 旋转轴:Inspector 中 Transform 的旋转数值

TransformExample1

对于这一个情况,Unity Doc 中有明确的说明,

The position, rotation and scale values of a Transform are measured relative to the Transform’s parent. If the Transform has no parent, the properties are measured in world space.

即,Editor中Transform组件的旋转轴是父节点的模型空间坐标轴,如果没有父节点,则旋转轴是世界空间坐标轴。

unity_transform

上图显示了如果Transform有父节点,如图中的”Mesh”,则Position将是在其父节点(这里是”Cow”)的模型空间中的位置;如果没有父节点,Position就是在世界空间中的位置。同样,Transform中的Rotation和Scale也是相同的道理。

2. 旋转轴:在Script中使用Rotate函数,在Space.Self中旋转

public void Rotate(Vector3 eulerAngles, Space relativeTo = Space.Self);
public void Rotate(float xAngle, float yAngle, float zAngle, Space relativeTo = Space.Self);
public void Rotate(Vector3 axis, float angle, Space relativeTo = Space.Self);

有上述三种重载函数,这里主要以第一种为例。其中第二个参数的取值有两种:Space.Self 或者 Space.World。

使用如下代码,测试上述函数的作用。

using UnityEngine;
using System.Collections;

public class Rotate : MonoBehaviour {
    public Space m_RotateSpace;
    public float m_RotateSpeed = 20f;

    // Update is called once per frame
    void Update()
    {
        transform.Rotate(Vector3.up * m_RotateSpeed * Time.deltaTime, m_RotateSpace);
    }
}

场景中进行测试的是一个长方体,其父节点的旋转为(30,30,0),圆柱体的初始旋转为(0,0,0)。在Inspector中将Rotate Space设置为Self后,运行结果见下图。可见,长方体是绕着局部坐标系的Y轴旋转的。

得出结论:在Space.Self中进行旋转,旋转轴就是局部坐标系的坐标轴。

RotateSpaceSelf

3. 旋转轴:在Script中使用Rotate函数,在Space.World中旋转

在Inspector中将Rotate Space设置为World后,运行结果见下图。这里我们知道,长方体的父节点的Y轴不是World的Y轴,而这里的长方体是绕着世界坐标系下的Y轴旋转的。

所以得出结论:在Space.World中进行旋转,旋转轴是世界坐标系的坐标轴。

RotateSpaceWorld

4. 静态欧拉角和动态欧拉角

前面说到的旋转轴的问题,在数学上有对应的概念。这就是所谓的静态欧拉角和动态欧拉角。

所谓静态欧拉角,就是其旋转轴使用的是静止不动的参考系。动态欧拉角,使用的是刚体本身作为参考系,因而参考系会随着刚体的旋转而旋转。

因此,使用Space.World旋转,以及Inspector中的旋转是静态欧拉角;使用Space.Self旋转,是动态欧拉角。

三、旋转的正方向

来到第二个问题,由于Unity中局部坐标系和世界坐标系都是左手坐标系,所以这里旋转的正方向可由右手法则判定。

四、旋转的顺序

下面来看第三个问题,旋转的顺序,即我们的欧拉角(xAngle, yAngle, zAngle)由三个分量组成,分别对应着绕x轴旋转,绕y轴旋转和绕z轴旋转,那么是如何绕着这三个轴进行旋转的呢?

这里也分为静态欧拉角和动态欧拉角的情况进行讨论。

1. 静态欧拉角

这种情况对应着上面所述的使用Space.World进行旋转,以及Inspector中的旋转。即使旋转轴在旋转的过程中保持不变,旋转的顺序会决定最后的旋转结果。我们看下面的例子会很清晰的理解:

  • 情形一:首先绕世界坐标系的x轴旋转90度,再绕世界坐标系的y轴旋转90度

RotateOrder1

  • 情形二:首先绕世界坐标系的y轴旋转90度,再绕世界坐标系的x轴旋转90度

RotateOrder2

可以看到,由于旋转顺序的不同,最终导致了旋转结果的不同!(究其本质,是因为矩阵乘法不满足交换律)

对于旋转的顺序,一般没有定式,因此,需要在使用时明确的指定出其顺序。对此有一个专门的术语,称为顺规。如果在坐标系中的旋转,先绕x轴旋转,再绕y轴,最后再绕z轴,则称之为X-Y-Z顺规。以此类推。

对于Unity,从文档中可以看到,其transform.Rotate()使用的是Z-X-Y顺规。因此如果在Unity中,使用静态欧拉角旋转(90,90,0)得到情形一的情况。

2. 动态欧拉角

这种情况对应着上面所述的使用Space.Self进行旋转。动态欧拉角除了上面说到的顺规问题(同样是Z-X-Y顺规),还有一个疑问:比如一个物体,初始状态记为A,以Z-X-Y顺规旋转(90,90,0),由于没有z轴旋转,第一步当然是绕着当前的x轴旋转90度,此时状态记为B,那么第二步要绕着y轴旋转90的时候,是绕着初始状态A时的y轴旋转,还是绕着此时的B状态下的y轴旋转呢?

首先来看下两者的区别:

  • 情形一:以状态A时的y轴旋转

RotateOrder3

  • 情形二:以状态B时的y轴旋转

RotateOrder4

Unity中的情况究竟如何呢?直接运行下面的代码会看到结果:

void Start () {
    transform.Rotate(90, 90, 0, Space.Self);
}

RotateOrder5

可以发现Unity中的情况与情形一相同。所以第二步要绕着y轴旋转90的时候,是绕着初始状态A时的y轴旋转。

为了得到情形二中的效果,可以分两次旋转,运行如下代码:

void Start () {
    transform.Rotate(90, 0, 0, Space.Self);
    transform.Rotate(0, 90, 0, Space.Self);
}

可以发现,此时的效果与情形一中相同了。

最终,我们的结论是:Unity中每次使用Space.Self进行Rotate时,都是绕着调用时刻的局部坐标系的坐标轴进行旋转的。

3. 静态欧拉角和动态欧拉角的等价形式

静态欧拉角和动态欧拉角是可以相互转换的。

转化规则就是:静态欧拉角中,在某一坐标系E下按照某一顺规如X-Y-Z旋转角度(a, b, c),等价于动态欧拉角中,在E下旋转(0, 0, c),在旋转后的坐标系E’中旋转(0, b, 0),在旋转后的新坐标系E”中旋转(a, 0, 0)。

在Space.Self中旋转以 Z-X-Y 顺规旋转角度(a, b, c),等价于在Space.Self中旋转(0, b, 0),在新的Space.Self中旋转(a, 0, 0),在更新的Space.Self中旋转(0, 0, c)。

下面我们来证明上述两种旋转是等价的。通过复合旋转矩阵的方式。

记:

绕坐标系E下的Z轴旋转c的旋转矩阵为Rz,
绕坐标系E下X轴旋转a的旋转矩阵为Rx,
绕坐标系E下Y轴旋转b的旋转矩阵为Ry;

绕坐标系E下的Y轴旋转b的矩阵为Rb(Rb == Ry),
绕坐标系E在绕Y轴旋转b后的新坐标系E’下的X轴旋转a的旋转矩阵为Ra,
绕坐标系E’在绕X轴旋转a后的新坐标系E”下的Z轴旋转c的旋转矩阵为Rc。

另外,这里将矩阵R的逆记为R~。

求证:Rz * Rx * Ry == Rb * Ra * Rc

证明:
Rb == Ry,由定义相同可知。
Ra = (Rb~) * Rx * Rb,要得到绕坐标系E在绕Y轴旋转b后的新坐标系E’下的X轴旋转a的旋转矩阵Ra,先应用Rb~旋转到坐标系E下,然后绕坐标系E下的X轴旋转a,最后应用Rb转回到坐标系E’。
Rc = ((Rb * Ra)~) * Rz * (Rb * Ra),理由同上。
所以有,
右边 = Rb * Ra * Rc
= Rb * Ra * ((Rb * Ra)~) * Rz * (Rb * Ra)
= Rz * Rb * Ra
= Rz * Rb * (Rb~) * Rx * Rb
= Rz * Rx * Rb
= Rz * Rx * Ry = 左边
证毕!

从代码上来说,就是下面两个函数是等价的。

private void RotateStatic(float a, float b, float c)
{
    // 静态欧拉角,依次绕着调用Rotate时的局部坐标系的z,x,y轴旋转a,b,c角度
    transform.Rotate(a, b, c, Space.Self);
}

private void RotateDynamic(float a, float b, float c)
{
    // 动态欧拉角,绕着调用Rotate时的局部坐标系的y轴旋转b角度
    transform.Rotate(0, b, 0, Space.Self);
    // 动态欧拉角,绕着调用Rotate时的局部坐标系的y轴旋转a角度
    transform.Rotate(a, 0, 0, Space.Self);
    // 动态欧拉角,绕着调用Rotate时的局部坐标系的y轴旋转c角度
    transform.Rotate(0, 0, c, Space.Self);
}

五、万向节锁(Gimbal Lock)

1. 什么是万向节锁

2. 如何产生万向节锁

3. 万向节锁的问题

3. 在欧拉旋转中尽力避免万向节锁

六、四元数(Quaternion)旋转

1. 什么是四元数

2. 用四元数进行旋转

参考

  1. Unity 中的旋转
  2. 欧拉角与万向节死锁
  3. 《Unity Shader 入门精要》第四章
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

[Unity] Unity 3D 中的旋转 的相关文章

  • unity粒子特效附上贴图后播放动画

    转自 http jingyan baidu com article f96699bbb1a0d6894f3c1b77 html 参考 http www unitymanual com thread 2993 1 1 html dsign a
  • UnityLuaMvvM Lua 带通知的Mode类

    实现数据更新UI自动刷新的核心代码 欢迎关注https gitee com xiongks UnityMVVM mode function modeType local obj obj modeType modeType obj filds
  • unity game界面按下play会不断闪烁,按下暂停键(pause)或者中止/下一步(step),game界面的画面会接连变化

    没找到答案 改了两个下午的程序 改完还是这样 后来发现是FixedUpdate Update与OnDrawGizmos的问题 OnDrawGizmos是每帧都会绘制 用FixedUpdate理所当然就那啥了 分析的时候 就突然想到是不是这俩
  • using UnityEditor引用注意事项

    本文转载自http blog csdn net czlilove article details 19979725 在运行时脚本中使用UnityEditor命名空间 假如该脚本被挂在场景中的物体上 那么 可以这样做 在Unity编辑器中运行
  • Unity WebGL错误集锦

    ips 0 Unity的PlayerSettings的otherSettings或者Publish Settings里面的Enable Exceptions里面选择Full StackTrace 可以在打出的包中的浏览器的webgl打印出错
  • 1.17 从0开始学习Unity游戏开发--场景切换

    前面的所有文章我们都在一个固定的游戏场景内进行开发 在最开始介绍场景这个概念的时候就已经提及 这个场景可以是一张地图 或者是一个对战房间等等 所以显然这个场景可以有多个 并且可以从一个场景切换到另外一个场景 那么在Unity中如何进行场景切
  • c#获取cpu序列号

  • Unity动画控制器animator.CrossFade

    需要特别注意 1 CrossFade虽然可以不用任何逻辑来链接而直接跳转 但是CrossFade只能覆盖其他动画 当当前动画播放完毕而没有跳出这个动画时再次调用CrossFade将会失败 造成动画依旧停在原位 参数animator Cros
  • Unity Shader入门精要第七章 基础纹理之遮罩纹理

    Unity系列文章目录 文章目录 Unity系列文章目录 前言 一 实践 参考 前言 遮罩纹理 mask texture 是本章要介绍的最后一种纹理 它非常有用 在很多商业游戏中 都可以见到它的身影 那么什么是遮罩呢 简单来讲 遮罩允许我们
  • Unity动画系统详解

    目录 动画编辑器 编辑器面板 动画复用 前言 人形重定向动画 Humanoid 通用动画 Generic 旧版本动画 Legacy 动画控制器 系统状态 切换条件 状态机脚本 IK动画 反向动力学 BlendTree 混合树 Animato
  • Unity中实现倒计时的几种方式

    1 Time time using UnityEngine public class TimeTest MonoBehaviour public float secound 10 void Update Timing private flo
  • Unity 键盘控制人物移动——之输入方式代码的编写

    键盘输入 控制人物移动 在我们制作游戏中最常见的需求之一就是使用键盘移动游戏角色 那么我们首先需要获取键盘输入 以下提供两种方法获取键盘 这里尽量通过截图解释让大家理解代码的含义 GetInput void FixedUpdate Move
  • unity实现鼠标右键控制视角

    主要实现的功能是相机跟随主角 鼠标右击移动后 相机的视角会旋转 思路 在主角里创建空的子物体 把相机绑在空物体上 通过旋转空物体来实现视角的旋转 要把相机调整到适当位置 代码如下 public float rotateSpeed 100 设
  • unity3d切换场景Application.LoadLevel(1)含义

    Application LoadLevel 1 场景ID
  • Unity万向节死锁解决方案(2023/12/4)

    1 万向节死锁无法解决 这是因为它的特性就是如此 就像玻璃杯就是玻璃 这不可否认 别钻牛角尖昂 2 大多数情况下欧拉角足够用 例如 CF 摄像机不可能绕z轴旋转 x轴旋转也不会超过九十度 因为那样人物的腰子会被扭断 塔防游戏 保卫萝卜 吃鸡
  • 【Unity】运行时创建曲线(贝塞尔的运用)

    Unity 运行时创建线 贝塞尔的运用 1 实现的目标 在运行状态下创建一条可以使用贝塞尔方法实时编辑的网格曲线 2 原理介绍 2 1 曲线的创建 unity建立网格曲线可以参考 Unity程序化网格体 的实现方法 主要分为顶点 三角面 U
  • Unity学习笔记

    一 旋转欧拉角 四元数 Vector3 rotate new Vector3 0 30 0 Quaternion quaternion Quaternion identity quaternion Quaternion Euler rota
  • Unity中URP下的指数雾

    文章目录 前言 一 指数雾 雾效因子 1 FOG EXP 2 FOG EXP2 二 MixFog 1 ComputeFogIntensity 雾效强度计算 2 lerp fogColor fragColor fogIntensity 雾效颜
  • 游戏开发常用实践操作之按动任意键触发

    接下来一些笔记会对于一些大大小小的实践操作进行记录 希望对你有所帮助 在游戏中 我们经常会遇到一些按动任意键触发的操作 接下来展示核心代码 以下是对于Unity中的操作 使用的UI是NGUI 对于核心操作没有影响 你可以自己置换 void
  • 游戏开发常见操作系列之敌人系统的开发一(U3D)

    在开发游戏的过程中 我们常常会出现一些敌人攻击我们玩家 并且实现掉血以及死亡的现象 敌人还会源源不断地生成 这是怎么制作的呢 接下来为大家提供方法 其中使用了NGUI 后续会更新其它方法 敬请期待 使用HUDText实现扣血时显示文本 直接

随机推荐

  • 【国赛清单】2023全国大学生电赛综合测试【总结】

    综合测评简介 1 综合测评是全国大学生电子设计竞赛评审工作中非常重要的一个环节 是 一次竞赛二级评审 工作中全国专家组评审工作的一部分 2 测试对象为赛区推荐上报全国评奖的优秀参赛队全体队员 以队为单位在各赛区以全封闭方式进行 测试现场必须
  • git上传文件到远程分支

    1 进入文件目录 kernel 执行make distclean 清除配置文件 2 查看所在分支 git branch a 3 查看远程分支 git branch r 3 添加文件到分支 git add git commit m XXXX
  • C++ 数据类型

    C 数据类型 使用编程语言进行编程时 需要用到各种变量来存储各种信息 变量保留的是它所存储的值的内存位置 这意味着 当您创建一个变量时 就会在内存中保留一些空间 您可能需要存储各种数据类型 比如字符型 宽字符型 整型 浮点型 双浮点型 布尔
  • Nginx配置白名单访问

    一 背景 在项目运行的时候 需要设置特定的访问权限 以拒绝其他可能存在的恶意访问 二 配置 2 1 关键字 允许访问关键字 allow 屏蔽访问关键字 deny 2 2 作用域 作用域如下 http 所有网站屏蔽IP server 单独网站
  • 字符串汇总

    一 字符串表达式计算 如 1 2 2 3 package TcpIO import java util Deque import java util LinkedList public class StringCalculate stati
  • 解决问题——无法连接到更新服务器。我们将稍后再试,你也可以立即进行检查。如果问题仍然存在,请确保你已连接到Internet

    安装AE跳出安装失败 错误 另一个安装程序当前正在运行 如需安装此产品 您必须将其关闭 请将其关闭 或者等待其他安装jieshu 错误代码 81 2 针对以上问题决定对Win10进行系统的更新 打开设置 更新与安全 进行更新 但是我的电脑更
  • 网段192.168.1.0/24是什么意思?

    192 168 1 0 24表示网段是192 168 1 0 子网掩码是24位 子网掩码为 255 255 255 0 用二进制表示为 11111111 11111111 11111111 00000000 这里为什么是24呢 就是因为子网
  • 公司计算机程序员英语作文,IT行业程序员英文简历模板范文

    英文简历的目的是帮助IT行业求职者获得面试机会 那你知道英文简历该怎么写吗 下面是学习啦小编为大家带来的程序员英文简历范文 相信对你会有帮助的 程序员英文简历范文 一 27 Hawkins Road Clarksboro New Jerse
  • Matlab 显示追踪点云 PLY格式

    用的matlab 可以用来显示文件夹下的所有ply点云 path strcat E WorkDatas argoverse tracking train1 dcdcd8b3 0ba1 3218 b2ea 7bb965aad3f0 lidar
  • 浅谈定时器及定时器在Vue项目中的使用

    对于一位前端工程师来说 说到定时器 想必都不陌生 无论是刚开始码农生活的新人还是多年工作经验的大牛 setTimeout setInterval 在项目中不可避免的都会使用 作为一个前端小菜鸟 在项目中的监控大屏的列表中需要用到setInt
  • 基于STM32CubeMX+FreeRTOS的Proteus仿真LCD1602

    LCD1602液晶显示器是广泛使用的一种字符型液晶显示模块 它是由字符型液晶显示屏 LCD 控制驱动主电路HD44780及其扩展驱动电路HD44100 以及少量电阻 电容元件和结构件等装配在PCB板上而组成 一 LCD1602技术参数 显示
  • docker 无法访问web

    出于安全考虑 Linux系统默认是禁止数据包转发的 所谓转发即当主机拥有多于一块的网卡时 其中一块收到数据包 根据数据包的目的ip地址将数据包发往本机另一块网卡 该网卡根据路由表继续发送数据包 这通常是路由器所要实现的功能 要让Linux系
  • PaddleDetection使用教程

    详细的使用教程可以参考官方文档 一 安装说明 在安装PaddleDetection之前要先安装依赖项PaddlePaddle 你可以将其看作一个内核 有了它才可以安装PaddleDetection 首先 我们可以新建一个虚拟环境 命名为pa
  • python每日一题(leetcode/atcoder/nowcoder)

    背景 用leetcode每日一题 正好练一练python的一些写法吧 2021年2月28日 896 单调队列 判断数组是单增的或者是单减的 学习到一个sorted的用法 还有倒序的切片 class Solution def isMonoto
  • 微信小程序java+ssm+uniapp个人理财消费收支系统

    利用Java语言 SSM框架和mysql数据库等知识点 结合相关设计模式 以及软件工程的相关知识 设计一个ssm微信小程序的个人消费系统 来进行记录用户的信息 以及小程序信息的增删改查的功能 根据实现需求 小程序需完成这些基本功能 1 系统
  • C++ 多态(一) : 多态的构成条件、final、override、协变、析构函数的重写、抽象类

    文章目录 1 多态的定义和实现 多态的浅层理解 多态的构成条件 2 虚函数 虚函数的重写规则 虚函数重写条件的两个例外 1 协变 返回值不同 2 析构函数的重写 函数名不同 3 C 11 override 和 final override
  • JQ开发中遇到的问题(一)

    目录 目录 1 收藏与取消收藏切换 2 使用layui插件下拉选择渲染问题 1 收藏与取消收藏切换 说明 从接口中获取收藏状态 单击切换状态 如下图所示 开始状态 点击后状态 代码实现 1 全局定义一个变量 记录状态 var collect
  • wps 云文档的服务器地址,在WPS云文档保存、管理文件

    云文档上传和获取服务端调用 目录 1 获取APP剩余空间 获取APP剩余空间 接口说明 获取APP剩余空间 请求说明 参数说明参数参数类型是否必须说明access tokenstringrequiredaccess token appids
  • 相关系数和p值的含义

    相关系数就是两个变量之间的相关程度 1 lt 0负相关 r gt 0正相关 r2越接近1表示越相关 P值即概率 反映某一事件发生的可能性大小 统计学根据显著性检验方法所得到的P 值 一般以P lt 0 05 为显著 P lt 0 01 为非
  • [Unity] Unity 3D 中的旋转

    Unity 3D 中的旋转 一 Unity 3D 中 Rotation 在Unity中 旋转通常可以用一个三维向量 x y z 表示 实际上这是欧拉角 三个分量分别是绕x轴 y轴和z轴的旋转角度 要对一个GameObject进行旋转 可以直