草庐IT

欧拉角、四元数与旋转

星际行走 2023-08-23 原文

欧拉角

使用三个角度来保存方位,如(0, 50, 0)。

X和Z沿自身坐标系旋转,Y沿世界坐标系旋转。

获取物体欧拉角:Vector3 eulerAngle = transform.eulerAngles;

优点:

1、仅使用三个数字保存方位,占用空间小。

2、沿坐标轴旋转的单位为角度,符合人的思考方式。

3、任意三个数字都是合法的,不存在不合法的欧拉角。

缺点:

一、方位的表达方式不唯一

1、对于一个方位,存在多个欧拉角描述,因此无法判断多个欧拉角代表的角位移是否相同

例如:

-- 角度0,5,0与角度0,365,0

-- 角度0,-5,0与角度0,355,0

-- 角度250,0,0与角度290,180,180

前面两种还好,第三种就比较复杂了。

2、为了保证方位表达方式唯一,unity限制了角度范围,即沿X轴旋转限制在-90到90之间,沿Y与Z旋转限制在-180到180之间。(实测,代码中修改欧拉角会受这个限制,之间在场景中修改欧拉角不受该限制)

这里就有个问题,如果修改欧拉角的x值,想让物体一直旋转,但是达到限制角度后,物体就不会继续旋转了。

二、万向节死锁

物体沿X轴旋转±90度,自身坐标系Z轴与世界坐标系Y轴将会重合,此时再沿Y轴或Z轴旋转时,将失去一个自由度。

在万向节死锁情况下,规定沿Z轴完成绕竖直轴的旋转,即此时Y轴旋转为0。

四元数

四元数Quaternion在3D图形学中代表旋转,由一个三维向量(x/y/z)和一个标量(w)组成

旋转轴为V,旋转弧度为θ,如果使用四元数表示,则四个分量为:

x=sin(θ/2)*V.x

y=sin(θ/2)*V.y

z=sin(θ/2)*V.z

w=cos(θ/2)

x、y、z、w的取值范围是-1到1.

Quaternion qt = transform.rotation;
transform.rotation = Quaternion.Euler(0, 50, 0);

优点:避免万向节死锁

缺点:

1、难于使用,不建议单独修改某个数值。

2、存在不合法的四元数。

与向量相乘

四元数左乘向量,表示将该向量按四元数表示的角度旋转

Vector3 newVec3 = Quaternion.Euler(0, 30, 0) * new Vector3(0, 0, 10);

如计算物体右前方30度,10m远坐标。

Vector3 vec3 = transform.rotation * new Vector3(0, 0, 10);
vec3 = Quaternion.Euler(0, 30, 0) * vec3;
vec3 = transform.position + vec3;

与四元数相乘

两个四元数相乘可以组合旋转效果

Quaternion q1 = Quaternion.Euler(0, 20, 0) * Quaternion.Euler(0, 30, 0);
Quaternion q2 = Quaternion.Euler(0, 50, 0);
// q1和q2相同

transform.rotation *= Quaternion.Euler(0, 1, 0);    // 沿自身y轴旋转
transform.Rotate(0, 1, 0);  // 内部就是使用四元数相乘实现

四元数实战:炸弹-障碍物-玩家范围判定

问题如下图:

这里只讨论求出两个切点。思路见下图:

计算出两个切点坐标后,计算两切线是否与障碍物相交,即可判定玩家是否被炸伤。

代码如下:

public Transform tranPlayer;
private float playRadius = 0.5f;

public Vector3 leftTangetPoint; // 左切点
public Vector3 rightTangetPoint; // 右切点

// 计算切点
void CalculateTangent()
{
    Vector3 playerPos = tranPlayer.position;
    Vector3 playerToBomb = transform.position - playerPos;
    Vector3 playerToBombRadius = playerToBomb.normalized * playRadius;  // 半径向量
    float angles = Mathf.Acos(playRadius / playerToBomb.magnitude) * Mathf.Rad2Deg;

    leftTangetPoint = playerPos + Quaternion.Euler(0, angles, 0) * playerToBombRadius;  // 用四元数旋转半径向量
    rightTangetPoint = playerPos + Quaternion.Euler(0, -angles, 0) * playerToBombRadius;
}

void Update()
{
    CalculateTangent();
    Debug.DrawLine(transform.position, leftTangetPoint);
    Debug.DrawLine(transform.position, rightTangetPoint);
}

四元数API的应用示例

public Transform tf;
//1、欧拉角转四元数
Quaternion.Euler(0, 50, 0);

//2、四元数转欧拉角
Quaternion qt = transform.rotation;
Vector3 euler = qt.eulerAngles;

//3、沿任意轴旋转角度,参数2可以传任意向量作为轴
transform.rotation = Quaternion.AngleAxis(50, Vector3.up);

//4、z轴指向一个方向, transform的z轴指向tf所在位置
Vector3 dir = tf.position - transform.position; // 方向向量
transform.rotation = Quaternion.LookRotation(dir);  // 根据方向向量,求出对应的四元数


// 按给定速度旋转
Quaternion qTarget = Quaternion.LookRotation(tf.position - transform.position);
//5、匀速旋转,z轴指向目标
transform.rotation = Quaternion.RotateTowards(transform.rotation, qTarget, 0.05f);
//6、插值旋转,z轴指向目标
transform.rotation = Quaternion.Lerp(transform.rotation, qTarget, 0.01f);
//7、求两四元数的夹角
if (Quaternion.Angle(qTarget, transform.rotation) < 1)
{
    transform.rotation = qTarget;
}


//X轴注视旋转
//8、x轴注视旋转, transform.right可以get和set
transform.right = tf.position - transform.position;
//9、x轴注视旋转。创建四元数,从开始方向旋转到目标方向
transform.rotation = Quaternion.FromToRotation(transform.right, tf.position - transform.position);

Transform的旋转函数

一、绕轴点旋转

public void RotateAround(Vector3 point, Vector3 axis, float angel);

功能是使得GameObject对象绕着point点的axis方向旋转angle度。

二、Rotate旋转

public void Rotate(float xAngle, float yAngle, float zAngle);
public void Rotate(Vector3 eulers, [DefaultValue("Space.Self")] Space relativeTo);
public void Rotate(Vector3 eulers);
public void Rotate(float xAngle, float yAngle, float zAngle, [DefaultValue("Space.Self")] Space relativeTo);
public void Rotate(Vector3 axis, float angle, [DefaultValue("Space.Self")] Space relativeTo);
public void Rotate(Vector3 axis, float angle);

三、LookAt指向目标旋转

默认是z轴指向,也可以设置其他轴或方向指向。

public void LookAt(Transform target, [DefaultValue("Vector3.up")] Vector3 worldUp);
public void LookAt(Vector3 worldPosition, [DefaultValue("Vector3.up")] Vector3 worldUp);
public void LookAt(Vector3 worldPosition);
public void LookAt(Transform target);

有关欧拉角、四元数与旋转的更多相关文章

  1. 旋转矩阵的几何意义 - 2

    点向量坐标矩阵的几何意义介绍旋转矩阵的几何含义之前,先介绍一下点向量坐标矩阵的几何含义点:在一维空间下就是一个标量,如同一条直线上,以任意某一个位置为0点,以一定的尺度间隔为1,2,3...,相反方向为-1,-2,-3...;如此就形成了一维坐标系,这时候任何一个点都可以用一个数值表示,如点p1=5,即即从原点出发沿着x轴正方向移动5个尺度;点p2=-3,负方向移动3个尺度;     在一维坐标系上过原点做垂直于一维坐标系的直线,则形成了二维坐标系,此时描述一个点需要两个数值来表示点p3=(3,2),即从原点出发沿着x轴正方向移动3个尺度,在此基础上沿着y轴正方向移动两个尺度的位置就是点p3。

  2. Unity 3D 制作开关门动画,旋转门制作,推拉门制作,门把手动画制作 - 2

    Unity自动旋转动画1.开门需要门把手先动,门再动2.关门需要门先动,门把手再动3.中途播放过程中不可以再次进行操作觉得太复杂?查看我的文章开关门简易进阶版效果:如果这个门可以直接打开的话,就不需要放置"门把手"如果门把手还有钥匙需要旋转,那就可以把钥匙放在门把手的"门把手",理论上是可以无限套娃的可调整参数有:角度,反向,轴向,速度运行时点击Test进行测试自己写的代码比较垃圾,命名与结构比较拉,高手轻点喷,新手有类似的需求可以拿去做参考上代码usingSystem.Collections;usingSystem.Collections.Generic;usingUnityEngine;u

  3. 欧拉角表示的姿态矩阵(313和312转序) - 2

    一、习惯约定图片来自PSINS(高精度捷联惯导算法)PSINS工具箱入门与详解.pptx二、基本旋转矩阵绕x轴逆时钟旋转α\alphaα角度Rx(α)=[ 1000cos⁡αsin⁡α0−sin⁡αcos⁡α]R_x(\alpha)=\begin{bmatrix}\1&0&0\\0&\cos\alpha&\sin\alpha\\0&-\sin\alpha&\cos\alpha\end{bmatrix}Rx​(α)=​ 100​0cosα−sinα​0sinαcosα​​绕y轴逆时钟旋转α\alphaα角度Ry(α)=[ cos⁡α0−sin⁡α010sin⁡α0cos⁡α]R_y(\alpha

  4. 欧拉角、旋转矩阵及四元数 - 2

    欧拉角、旋转矩阵及四元数1.简介2.欧拉角2.1欧拉角定义2.2右手系和左手系2.3转换流程3.旋转矩阵4.四元数4.1四元数与欧拉角和旋转矩阵之间等效变换4.2测试Matlab代码5.总结1.简介常用姿态参数表达方式包括方向余弦矩阵、欧拉轴/角参数、欧拉角、四元数以及罗德里格参数等。高分辨率光学遥感卫星主要采用欧拉角与四元数对姿态参数进行描述。这里着重讲解欧拉角、旋转矩阵和四元数。2.欧拉角2.1欧拉角定义欧拉角是表征刚体旋转的一种方法之一,由莱昂哈德·欧拉引入的三个角度,用于描述刚体相对于固定坐标系的方向。在摄影测量、空间科学或其它技术领域,一般用一组(三个)欧拉角描述两个空间坐标之间的旋

  5. ruby - 我可以在传递给方法的 block 上强制执行元数吗? - 2

    有什么方法可以“开启”使用Proc.new或Kernel.proc实例化的Proc的严格元数强制执行,使其表现得像Proc用lambda实例化?我的initialize方法采用block&action并将其分配给实例变量。我希望action严格执行arity,因此当我稍后对其应用参数时,它会引发一个ArgumentError,我可以挽救它并引发一个更有意义的异常。基本上:classCommandattr_reader:name,:actiondefinitialize(name,&action)@name=name@action=actionenddefperform(*args)be

  6. 欧拉系统安装与部署NextCloud及数据迁移 - 2

    欧拉系统部署NextCloud与常见部署问题解决以及数据盘迁移一、欧拉系统安装二、openEuler安装图形界面Ukui三、yum安装的npm包进行本地保存设置(个人任务需要)四、部署nextCloud4.1构建LAMP环境基础4.1.1开启httpd,防火墙端口号4.1.2开启MariaDB服务4.1.3安装并测试php4.2下载安装nextCloud4.2.1创建nextCloud数据库,存放网盘文件索引与用户信息4.2.2拷贝NextCloud并创建data目录,目录赋予权限五、离线npm包方式部署NextCloud(个人需要,正常联网状态搭建LAMP环境后,拷贝NextCloud安装即

  7. ruby - 欧拉计划 1 :Find the sum of all the multiples of 3 or 5 below 1000 - 2

    我正在尝试使用ProjectEuler中的Ruby解决数学问题。Here是我尝试的第一个:Ifwelistallthenaturalnumbersbelow10thataremultiplesof3or5,weget3,5,6and9.Thesumofthesemultiplesis23.Findthesumofallthemultiplesof3or5below1000.请帮助我改进我的代码。total=0(0...1000).eachdo|i|total+=iif(i%3==0||i%5==0)endputstotal 最佳答案

  8. ruby - 如何获取 "super"的元数? - 2

    假设您正在用不同的元数覆盖子类中的方法:classAdeffoo(arg)#arityis1#doingsomethinghereendendclassB有没有办法在线获取super的元数?(实际用例:我调用super时知道父类(superclass)不接受任何参数。但是,如果父类(superclass)实现(在gem中)发生变化,我想发出警告。)感谢您的帮助! 最佳答案 关于您的实际用例:无需亲自检查参数。打电话super(arg1)如果参数计数不匹配,Ruby将引发ArgumentError。更新由于一些反对票,我想我应该回答你

  9. 华为OD机试 -旋转骰子(Python) | 机试题算法思路 【2023】 - 2

    最近更新的博客华为OD机试-卡片组成的最大数字(Python)|机试题算法思路华为OD机试-网上商城优惠活动(一)(Python)|机试题算法思路华为OD机试-统计匹配的二元组个数(Python)|机试题算法思路华为OD机试-找到它(Python)|机试题算法思路华为OD机试-九宫格按键输入(Python)|机试算法备考思路华为OD机试-身高排序(Python)|备考思路使用说明参加华为od机试,一定要注意不要完全背诵代码,需要理解之后模仿写出,通过率才会高。华为OD清单查看地址:blog.csdn.net/hihell/catego

  10. ruby - 将元数据添加到 PDF - 2

    我需要将元数据添加到我使用prawn创建的PDF中.该元数据稍后可能会被pdf-reader提取。.此元数据将包含内部文档编号和下游工具所需的其他信息。将元数据与PDF的每一页相关联会很方便。ThePDFspecification声称我可以将每页私有(private)数据存储在“Page-PieceDictionary”中。第14.5节指出:Apage-piecedictionary(PDF1.3)maybeusedtoholdprivateconformingproductdata.ThedatamaybeassociatedwithapageorformXObjectbymeans

随机推荐