Unity3D - 详解Quaternion类(二)

2024-06-19 19:48
文章标签 详解 unity3d quaternion

本文主要是介绍Unity3D - 详解Quaternion类(二),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

转自:http://www.cnblogs.com/tgycoder/p/5106463.html


四、Quaternion类静态方法

Quaternion中的静态方法有9个即:Angle方法、Dot方法、Euler方法、FromToRotation方法、Inverse方法、Lerp方法、LookRotation方法、RotateToWards方法和Slerp方法。关于静态的方法的使用就是直接用类名调用其静态方法,例如Quaternion.Angle(q1,q2);下面对这些静态方法做下分析。

1、Angle方法

1.1 函数原型
public static float Angle(Quaternion a,Quaternion b);

该方法可以计算两个旋转状态a达到b时需要旋转的最小夹角。

1.2 实例演示
复制代码
using UnityEngine;
using System.Collections;public class Angle_ts : MonoBehaviour {// Use this for initializationvoid Start () {Quaternion q1 = Quaternion.identity;Quaternion q2 = Quaternion.identity;q1.eulerAngles = new Vector3(30.0f, 40.0f, 50.0f);float a1 = Quaternion.Angle(q1, q2);float a2 = 0.0f;Vector3 v = Vector3.zero;q1.ToAngleAxis(out a2,out v);Debug.Log("a1: " + a1);Debug.Log("a2: " + a2);Debug.Log("q1的欧拉角: " + q1.eulerAngles + " q1的rotation: " + q1);Debug.Log("q2的欧拉角: " + q2.eulerAngles + " q2的rotation: " + q2);}// Update is called once per framevoid Update () {}
}
复制代码

运行结果

从输出结果可以看出a1和a2的值相等,即Angle的返回值是两个Quaternion实例转换的最小夹角。

2、Dot方法-点乘

2.1 函数原型
public static float Dot(Quaternion a,Quaternion b);

该方法可以根据点乘的结果,判断a和b对应欧拉角的关系。

例如有两个Quaternion实例q1(x1,y1,z1,w1)和q2(x2,y2,z2,w2),则float f = Quaternion.Dot(q1,q2);即f = x1*x2+y1*y2+z1*z2+w1*w2,结果值f的范围为[-1,1]。

当f=+(-)1时,q1和q2对应的欧拉角是相等的,即旋转状态是一致的。特别地,当f = -1时,说明其中一个rotation比另外一个rotation多旋转了360°。

2.2 实例演示
复制代码
using UnityEngine;
using System.Collections;public class Dot_ts : MonoBehaviour {public Transform A, B;Quaternion q1 = Quaternion.identity;Quaternion q2 = Quaternion.identity;// Use this for initializationvoid Start () {A.eulerAngles = new Vector3(0.0f, 40.0f, 0.0f);B.eulerAngles = new Vector3(0.0f, 360.0f + 40.0f, 0.0f);q1 = A.rotation;q2 = B.rotation;float f = Quaternion.Dot(q1, q2);Debug.Log("q1的欧拉角: " + q1.eulerAngles + " q1的rotation: " + q1);Debug.Log("q2的欧拉角: " + q2.eulerAngles + " q2的rotation: " + q2);Debug.Log("Dot(q1,q2): " + f);}// Update is called once per framevoid Update () {}
}
复制代码

运行输出

从输出结果可以证明q1和q2的欧拉角相等,但是rotation值却是相反的,也说明当Dot的返回值为-1时,两个参数的角度相差360°。

3、Euler方法

3.1 函数原型
public static Quaternion Euler(Vector3 euler);
public static Quaternion Euler(float x,float y,float z);

该方法用于返回欧拉角Vector3(ex,ey,ez)对应的四元数Quaternion q(qx,qy,qz,qw)。其对应关系如下:

已知PIover180 = 3.141592/180 = 0.0174532925f是计算机图形学中的一个常亮,其变换过程如下:

复制代码
ex = ex * PIover180 / 2.0f;
ey = ey * PIover180 / 2.0f;
ez = ez * PIover180 / 2.0f;qx = Mathf.Sin(ex) * Mathf.Cos(ey) * Mathf.Cos(ez) + Mathf.Cos(ex) * Mathf.Sin(ey) * Mathf.Sin(ez);
qy = Mathf.Cos(ex) * Mathf.Sin(ey) * Mathf.Cos(ez) - Mathf.Sin(ex) * Mathf.Cos(ey) * Mathf.Sin(ez);
qz = Mathf.Cos(ex) * Mathf.Cos(ey) * Mathf.Sin(ez) - Mathf.Sin(ex) * Mathf.Sin(ey) * Mathf.Cos(ez);
qw = Mathf.Cos(ex) * Mathf.Cos(ey) * Mathf.Cos(ez) + Mathf.Sin(ex) * Mathf.Sin(ey) * Mathf.Sin(ez);
复制代码
3.2 验证变换过程
复制代码
using UnityEngine;
using System.Collections;public class Euler_ts : MonoBehaviour {public float ex, ey, ez;float qx, qy, qz,qw;float PIover180 = 0.0174532925f;Quaternion q = Quaternion.identity;Vector3 euler;void OnGUI(){if(GUI.Button(new Rect(10.0f,10.0f,100.0f,45.0f),"计算")){euler = new Vector3(ex,ey,ez);Debug.Log("欧拉角Euler(ex,ey,ez): " + euler);q = Quaternion.Euler(ex, ey, ez);Debug.Log("对应的四元数为: " + q);Debug.Log("q.x: " + q.x + " q.y: " + q.y + " q.z: " + q.z + " q.w: " + q.w);//验证算法ex = ex * PIover180 / 2.0f;ey = ey * PIover180 / 2.0f;ez = ez * PIover180 / 2.0f;qx = Mathf.Sin(ex) * Mathf.Cos(ey) * Mathf.Cos(ez) + Mathf.Cos(ex) * Mathf.Sin(ey) * Mathf.Sin(ez);qy = Mathf.Cos(ex) * Mathf.Sin(ey) * Mathf.Cos(ez) - Mathf.Sin(ex) * Mathf.Cos(ey) * Mathf.Sin(ez);qz = Mathf.Cos(ex) * Mathf.Cos(ey) * Mathf.Sin(ez) - Mathf.Sin(ex) * Mathf.Sin(ey) * Mathf.Cos(ez);qw = Mathf.Cos(ex) * Mathf.Cos(ey) * Mathf.Cos(ez) + Mathf.Sin(ex) * Mathf.Sin(ey) * Mathf.Sin(ez);Debug.Log("qx: " + qx + " qy: " + qy + " qz: " + qz + " qw: " + qw);}}
}
复制代码

运行结果

从输出结果可以证明该公式是正确,另外转换后的四元数直接输出的话,如下:

 q = Quaternion.Euler(ex, ey, ez);Debug.Log("对应的四元数为: " + q);

输出值是做了四舍五入处理的。

4、FromToRotation方法

函数原型

public static Quaternion FromToRotation(Vector3 fromDirection,Vector3 ToDirection);

在前面介绍了SetFromToRotation实例方法,它们的功能都是一样的只不过用法稍有不同。使用FromToRotation类静态方法,需要直接使用类名进行调用,如Quaternion.FromToRotation(v1,v2);

在此就不做演示了!

5、Inverse方法

5.1 函数原型
public static Quaternion Inverse(Quaternion rotation);

该方法可以返回参数rotation的逆向Quaternion值。

例如rotation(x,y,z,w),那么Quaternion.Inverse(rotation) = (-x,-y,-z,w)。假设rotation的欧拉角为(a,b,c),则transform.rotation = Quaternion.Inverse(rotation)相当于transform依次绕自身坐标系的z轴、x轴和y轴分别旋转-c°、-a°和-z°。由于是在局部坐标系内的变换,最后transform的欧拉角的各个分量值并不一定等于-a、-b或-c。

5.2 实例演示
复制代码
using UnityEngine;
using System.Collections;public class Invers_ts : MonoBehaviour {public Transform A, B;// Use this for initializationvoid Start () {Quaternion q1 = Quaternion.identity;Quaternion q2 = Quaternion.identity;q1.eulerAngles = new Vector3(30.0f,40.0f,50.0f);q2 = Quaternion.Inverse(q1);A.rotation = q1;B.rotation = q2;Debug.Log("q1的欧拉角: " + q1.eulerAngles + "q1的rotation: " + q1);Debug.Log("q2的欧拉角: " + q2.eulerAngles + "q2的rotation: " + q2);}// Update is called once per framevoid Update () {}
}
复制代码

运行截图

6、Lerp和Slerp方法

6.1 函数原型
public static Quaternion Lerp(Quaternion form, Quaternion to,float t);
public static Quaternion Slerp(Quaternion form, Quaternion to,float t);

两种方法的作用都是返回从form到to的插值。当参数t<=0时返回值为from,当参数t>=1时返回值为to。其中Lerp是线性差值,而Slerp是球面插值。

6.2 实例演示
复制代码
using UnityEngine;
using System.Collections;public class LerpAndSlerp_ts : MonoBehaviour
{public Transform A, B, C,D;float speed = 0.2f;float total = 0.0f;// Use this for initializationvoid Start () {}// Update is called once per framevoid Update () {total += Time.deltaTime * speed;if(total >= 1.0f)total = 1.0f;C.rotation = Quaternion.Lerp(A.rotation, B.rotation, total);D.rotation = Quaternion.Lerp(A.rotation, B.rotation, total);//C.rotation = Quaternion.Lerp(A.rotation, B.rotation, Time.deltaTime * speed);//D.rotation = Quaternion.Lerp(A.rotation, B.rotation, Time.deltaTime * speed);
    }
}
复制代码

7、RotateTowards方法

7.1 函数原型
public static Quaternion RotateTowards(Quaternion from, Quaternion to, float maxDegreesDelta);

该方法也是一个插值方法,即从返回参数from到to的插值,且返回值的最大角度不超过maxDegreesDelta。maxDegreesDelta是角度值,不是插值系数,当maxDegreesDelta < 0时,将进行逆向插值即从to到from的方向进行插值计算。

7.2 实例演示
复制代码
using UnityEngine;
using System.Collections;public class RotateToWards_ts : MonoBehaviour {public Transform A, B, C;float speed = 10.0f;float total = 0.0f;// Use this for initializationvoid Start(){}// Update is called once per framevoid Update(){total += Time.deltaTime * speed;if (total >= 1.0f)total = 1.0f;C.rotation = Quaternion.RotateTowards(A.rotation, B.rotation, Time.time * speed - 40.0f);Debug.Log("C与A的欧拉角的插值: " + (C.eulerAngles - A.eulerAngles) + "maxDegreesDelta: " + (Time.time * speed - 40.0f));}
}
复制代码

运行截图

8、LookRotation方法

函数原型

public static Quaternion LookRotation(Vector3 forward);
public static Quaternion LookRotation(Vector3 forward,Vector3 upwards);

参数forward为返回Quaternion实例的forward朝向。该方法和前面讲到的SetLookRotation实例方法的功能是一样的,故不多做阐述了。

五、Quaternion类运算符

Quaternion类涉及到两个Quaternion对象相乘和Quaternion对象与Vector3对象相乘,那么就必须重载"*"运算符。

1、函数原型

public static Quaternion operator *(Quaternion lhs, Quaternion rhs);
public static Vector3 operator *(Quaternion rotation, Vector3 point);

2、两个Quaternion对象相乘

对于两个Quaternion对象相乘主要用于自身旋转变换,例如:

B.rotation *= A.rotation;
  • B会绕着B的局部坐标系的z、x、y轴按照先绕z轴再绕x轴最后绕y轴的旋转次序,分别旋转A.eulerAngles.z度、A.eulerAngles.x度、和A.eulerAngles.y度。由于是绕着局部坐标系进行旋转,所以当绕着其中一个轴进行旋转时,可能会影响其余两个坐标轴方向的欧拉角(除非其余两轴的欧拉角都为0才不会受到影响)。
  • 假如A的欧拉角为aEuler(ax,ay,az),则沿着B的初始局部坐标系的aEuler方向向下看B在绕着aEuler顺时针旋转。B的旋转状况还受到其初始状态的影响。
2.1 实例演示
复制代码
using UnityEngine;
using System.Collections;public class Multiply1_ts : MonoBehaviour {public Transform A, B;// Use this for initializationvoid Start () {A.eulerAngles = new Vector3(1.0f, 1.5f, 2.0f);}// Update is called once per framevoid Update () {B.rotation *= A.rotation;Debug.Log(B.eulerAngles);}
}
复制代码

运行截图

2.2 分析

B绕着其自身坐标系的Vector3(1.0f,1.5f,2.0f)方向旋转。虽然每次都绕着这个轴向旋转的角度相同,但角度的旋转在3个坐标轴的值都不为零,三个轴的旋转会相互影响,所以B的欧拉角的各个分量的每次递增是不固定的。

3、Quaternion对象与Vector3对象

对于Quaternion对象与Vector3对象相乘主要用于自身移动变换,例如

transform.position += tansform.rotation * A;

其中A为Vector3的对象。transform对应的对象会沿着自身坐标系中向量A的方向移动A的模长的距离。transform.rotation与A相乘可以确定移动的方向和距离。

3.1 实例演示
复制代码
using UnityEngine;
using System.Collections;public class Multiply2_ts : MonoBehaviour {public Transform A;float speed = 0.1f;// Use this for initializationvoid Start () {A.position = Vector3.zero;A.eulerAngles = new Vector3(0.0f, 45.0f, 0.0f);}// Update is called once per framevoid Update () {A.position += A.rotation * (Vector3.forward * speed);Debug.Log(A.position);}
}
复制代码

运行截图

4、两个Quaternion对象相乘与Quaternion对象与Vector3对象相乘的异同

  • 设A为两个两个Quaternion对象相乘的结果。B为Quaternion对象与Vector3对象相乘的结果。其中A为Quaternion类型,B为Vector3类型。
  • A与B的相同之处是它们都通过自身坐标系的“相乘”方式来实现在世界坐标系中的变换。
  • A主要用来实现transform绕自身坐标系的某个轴旋转,B主要用来实现transform沿着自身坐标系的某个方向移动。
  • 必须遵守Quaternion对象*Vector3对象的形式,不可以颠倒顺序。
  • 由于它们都是相对于自身坐标系进行的旋转或移动,所以当自身坐标系的轴向和世界坐标系的轴向不一致时,它们绕着自身坐标系中的某个轴向的变动都会影响到物体在世界坐标系中各个坐标轴的变动。

--------------------------------------------------------------------------------------------------------至此完结!-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

写代码是一种艺术,甚于蒙娜丽莎的微笑。

这篇关于Unity3D - 详解Quaternion类(二)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1075981

相关文章

Mysql数据库聚簇索引与非聚簇索引举例详解

《Mysql数据库聚簇索引与非聚簇索引举例详解》在MySQL中聚簇索引和非聚簇索引是两种常见的索引结构,它们的主要区别在于数据的存储方式和索引的组织方式,:本文主要介绍Mysql数据库聚簇索引与非... 目录前言一、核心概念与本质区别二、聚簇索引(Clustered Index)1. 实现原理(以 Inno

使用python生成固定格式序号的方法详解

《使用python生成固定格式序号的方法详解》这篇文章主要为大家详细介绍了如何使用python生成固定格式序号,文中的示例代码讲解详细,具有一定的借鉴价值,有需要的小伙伴可以参考一下... 目录生成结果验证完整生成代码扩展说明1. 保存到文本文件2. 转换为jsON格式3. 处理特殊序号格式(如带圈数字)4

MySQL数据库双机热备的配置方法详解

《MySQL数据库双机热备的配置方法详解》在企业级应用中,数据库的高可用性和数据的安全性是至关重要的,MySQL作为最流行的开源关系型数据库管理系统之一,提供了多种方式来实现高可用性,其中双机热备(M... 目录1. 环境准备1.1 安装mysql1.2 配置MySQL1.2.1 主服务器配置1.2.2 从

Linux kill正在执行的后台任务 kill进程组使用详解

《Linuxkill正在执行的后台任务kill进程组使用详解》文章介绍了两个脚本的功能和区别,以及执行这些脚本时遇到的进程管理问题,通过查看进程树、使用`kill`命令和`lsof`命令,分析了子... 目录零. 用到的命令一. 待执行的脚本二. 执行含子进程的脚本,并kill2.1 进程查看2.2 遇到的

MyBatis常用XML语法详解

《MyBatis常用XML语法详解》文章介绍了MyBatis常用XML语法,包括结果映射、查询语句、插入语句、更新语句、删除语句、动态SQL标签以及ehcache.xml文件的使用,感兴趣的朋友跟随小... 目录1、定义结果映射2、查询语句3、插入语句4、更新语句5、删除语句6、动态 SQL 标签7、ehc

详解SpringBoot+Ehcache使用示例

《详解SpringBoot+Ehcache使用示例》本文介绍了SpringBoot中配置Ehcache、自定义get/set方式,并实际使用缓存的过程,文中通过示例代码介绍的非常详细,对大家的学习或者... 目录摘要概念内存与磁盘持久化存储:配置灵活性:编码示例引入依赖:配置ehcache.XML文件:配置

从基础到高级详解Go语言中错误处理的实践指南

《从基础到高级详解Go语言中错误处理的实践指南》Go语言采用了一种独特而明确的错误处理哲学,与其他主流编程语言形成鲜明对比,本文将为大家详细介绍Go语言中错误处理详细方法,希望对大家有所帮助... 目录1 Go 错误处理哲学与核心机制1.1 错误接口设计1.2 错误与异常的区别2 错误创建与检查2.1 基础

k8s按需创建PV和使用PVC详解

《k8s按需创建PV和使用PVC详解》Kubernetes中,PV和PVC用于管理持久存储,StorageClass实现动态PV分配,PVC声明存储需求并绑定PV,通过kubectl验证状态,注意回收... 目录1.按需创建 PV(使用 StorageClass)创建 StorageClass2.创建 PV

Python版本信息获取方法详解与实战

《Python版本信息获取方法详解与实战》在Python开发中,获取Python版本号是调试、兼容性检查和版本控制的重要基础操作,本文详细介绍了如何使用sys和platform模块获取Python的主... 目录1. python版本号获取基础2. 使用sys模块获取版本信息2.1 sys模块概述2.1.1

一文详解Python如何开发游戏

《一文详解Python如何开发游戏》Python是一种非常流行的编程语言,也可以用来开发游戏模组,:本文主要介绍Python如何开发游戏的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下... 目录一、python简介二、Python 开发 2D 游戏的优劣势优势缺点三、Python 开发 3D